Added sharedMath and sharedRandom libraries

This commit is contained in:
Anonymous
2014-01-14 02:05:25 -07:00
parent 377fab52c5
commit a4f2c06f77
187 changed files with 21231 additions and 1 deletions
@@ -0,0 +1,133 @@
set(SHARED_SOURCES
shared/CatmullRomSpline.cpp
shared/CatmullRomSpline.h
shared/CompressedQuaternion.cpp
shared/CompressedQuaternion.h
shared/ConfigSharedMath.cpp
shared/ConfigSharedMath.h
shared/FirstSharedMath.h
shared/IndexedTriangleList.cpp
shared/IndexedTriangleList.h
shared/Line2d.h
shared/MxCifQuadTree.cpp
shared/MxCifQuadTree.h
shared/MxCifQuadTreeBounds.cpp
shared/MxCifQuadTreeBounds.h
shared/PackedArgb.cpp
shared/PackedArgb.h
shared/PackedRgb.cpp
shared/PackedRgb.h
shared/PaletteArgb.cpp
shared/PaletteArgb.h
shared/PaletteArgbList.cpp
shared/PaletteArgbList.h
shared/Plane.cpp
shared/Plane.h
shared/PolySolver.cpp
shared/PolySolver.h
shared/Quaternion.cpp
shared/Quaternion.h
shared/Rectangle2d.cpp
shared/Rectangle2d.h
shared/SetupSharedMath.cpp
shared/SetupSharedMath.h
shared/SpatialSubdivision.cpp
shared/SpatialSubdivision.h
shared/Sphere.cpp
shared/Sphere.h
shared/SphereTree.h
shared/SphereTreeNode.h
shared/Transform.cpp
shared/Transform.h
shared/Transform2d.cpp
shared/Transform2d.h
shared/Vector.cpp
shared/Vector.h
shared/Vector2d.h
shared/VectorArgb.cpp
shared/VectorArgb.h
shared/Volume.cpp
shared/Volume.h
shared/WaveForm.cpp
shared/WaveForm.h
shared/WaveForm3D.cpp
shared/WaveForm3D.h
shared/core/AxialBox.cpp
shared/core/AxialBox.h
shared/core/Capsule.cpp
shared/core/Capsule.h
shared/core/Circle.cpp
shared/core/Circle.h
shared/core/Cylinder.cpp
shared/core/Cylinder.h
shared/core/Line3d.cpp
shared/core/Line3d.h
shared/core/MultiShape.cpp
shared/core/MultiShape.h
shared/core/OrientedBox.cpp
shared/core/OrientedBox.h
shared/core/OrientedCircle.cpp
shared/core/OrientedCircle.h
shared/core/OrientedCylinder.cpp
shared/core/OrientedCylinder.h
shared/core/Plane3d.cpp
shared/core/Plane3d.h
shared/core/Quadratic.cpp
shared/core/Quadratic.h
shared/core/Range.cpp
shared/core/Range.h
shared/core/RangeLoop.cpp
shared/core/RangeLoop.h
shared/core/Ray3d.cpp
shared/core/Ray3d.h
shared/core/Ribbon3d.cpp
shared/core/Ribbon3d.h
shared/core/Ring.cpp
shared/core/Ring.h
shared/core/Segment3d.cpp
shared/core/Segment3d.h
shared/core/ShapeUtils.cpp
shared/core/ShapeUtils.h
shared/core/Torus.cpp
shared/core/Torus.h
shared/core/Triangle2d.cpp
shared/core/Triangle2d.h
shared/core/Triangle3d.cpp
shared/core/Triangle3d.h
shared/core/YawedBox.cpp
shared/core/YawedBox.h
shared/debug/DebugShapeRenderer.cpp
shared/debug/DebugShapeRenderer.h
)
if(WIN32)
set(PLATFORM_SOURCES
win32/FirstSharedMath.cpp
win32/SseMath.cpp
win32/SseMath.h
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/win32)
else()
set(PLATFORM_SOURCES "")
endif()
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/shared
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedDebug/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFile/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundation/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundationTypes/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMemoryManager/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedRandom/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedSynchronization/include/public
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/fileInterface/include/public
)
add_library(sharedMath STATIC
${SHARED_SOURCES}
${PLATFORM_SOURCES}
)
@@ -0,0 +1,42 @@
// ============================================================================
//
// CatmullRomSpline.cpp
// Copyright Sony Online Entertainment
//
// ============================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/CatmullRomSpline.h"
#include "sharedMath/Vector.h"
//-----------------------------------------------------------------------------
void CatmullRomSpline::getCatmullRomSplinePoint(float const c1x, float const c1y, float const c2x, float const c2y, float const c3x, float const c3y, float const c4x, float const c4y, float const t, float &resultX, float &resultY)
{
float const t3 = t * t * t;
float const t2 = t * t;
float const a = (-0.5f * t3 + t2 - 0.5f * t);
float const b = (1.5f * t3 - 2.5f * t2 + 1.0f);
float const c = (-1.5f * t3 + 2.0f * t2 + 0.5f * t);
float const d = (0.5f * t3 - 0.5f * t2);
resultX = c1x * a + c2x * b + c3x * c + c4x * d;
resultY = c1y * a + c2y * b + c3y * c + c4y * d;
}
//-----------------------------------------------------------------------------
void CatmullRomSpline::getCatmullRomSplinePoint3d(Vector const &c1, Vector const &c2, Vector const &c3, Vector const &c4, float const t, Vector &result)
{
float const t3 = t * t * t;
float const t2 = t * t;
float const a = (-0.5f * t3 + t2 - 0.5f * t);
float const b = (1.5f * t3 - 2.5f * t2 + 1.0f);
float const c = (-1.5f * t3 + 2.0f * t2 + 0.5f * t);
float const d = (0.5f * t3 - 0.5f * t2);
result.x = c1.x * a + c2.x * b + c3.x * c + c4.x * d;
result.y = c1.y * a + c2.y * b + c3.y * c + c4.y * d;
result.z = c1.z * a + c2.z * b + c3.z * c + c4.z * d;
}
// ============================================================================
@@ -0,0 +1,33 @@
// ============================================================================
//
// CatmullRomSpline.h
// Copyright Sony Online Entertainment
//
// ============================================================================
#ifndef INCLUDED_CatmullRomSpline_H
#define INCLUDED_CatmullRomSpline_H
class Vector;
//-----------------------------------------------------------------------------
class CatmullRomSpline
{
public:
static void getCatmullRomSplinePoint(float const c1x, float const c1y, float const c2x, float const c2y, float const c3x, float const c3y, float const c4x, float const c4y, float const t, float &resultX, float &resultY);
static void getCatmullRomSplinePoint3d(Vector const &c1, Vector const &c2, Vector const &c3, Vector const &c4, float const t, Vector &result);
private:
// Disabled
CatmullRomSpline();
CatmullRomSpline(CatmullRomSpline const &);
~CatmullRomSpline();
CatmullRomSpline &operator =(CatmullRomSpline const &);
};
// ============================================================================
#endif // INCLUDED_CatmullRomSpline_H
@@ -0,0 +1,637 @@
// ======================================================================
//
// CompressedQuaternion.cpp
// Copyright 2002 Sony Online Entertainment, Inc.
// All Rights Reserved.
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/CompressedQuaternion.h"
#include "sharedMath/Quaternion.h"
#include <limits>
#include <vector>
// ======================================================================
#if DEBUG_LEVEL == DEBUG_LEVEL_DEBUG
#define VERIFY_COMPRESSION 1
#else
#define VERIFY_COMPRESSION 0
#endif
// ======================================================================
namespace CompressedQuaternionNamespace
{
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
struct FormatPrecisionInfo
{
//-- Specified directly.
uint8 formatId;
uint8 baseIndexMask;
int baseCount;
float baseSeparation;
//-- Calculated.
float compressFactorElevenBit;
float expandFactorElevenBit;
float compressFactorTenBit;
float expandFactorTenBit;
};
#define MAKE_BASE_SEPARATION(baseShiftCount) (2.0f / static_cast<float>((0x01 << (baseShiftCount)) + 1))
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class FormatData
{
public:
FormatData();
void install(float baseValue, uint8 formatPrecisionIndex);
uint32 compressTenBit(float uncompressedValue) const;
uint32 compressElevenBit(float uncompressedValue) const;
float expandTenBit(uint32 compressedValue) const;
float expandElevenBit(uint32 compressedValue) const;
private:
float m_baseValue;
uint8 m_formatPrecisionIndex;
#ifdef _DEBUG
bool m_installed;
#endif
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// packed format: [MSB] x-11-bit y-11-bit z-10-bit
const uint32 cs_xShift = 21;
const uint32 cs_yShift = 10;
// Acceptable error in given w calculation from real w calculation.
const float cs_xAcceptableEpsilon = 0.001f;
const float cs_yAcceptableEpsilon = 0.001f;
const float cs_zAcceptableEpsilon = 2.0f * cs_xAcceptableEpsilon;
const float cs_wAcceptableEpsilon = 0.1f;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// 11-bit compressed format
const uint32 cs_valueMaskElevenBit = BINARY3(0011, 1111, 1111);
const uint32 cs_signBitElevenBit = BINARY3(0100, 0000, 0000);
// 10-bit compressed format
const uint32 cs_valueMaskTenBit = BINARY3(0001, 1111, 1111);
const uint32 cs_signBitTenBit = BINARY3(0010, 0000, 0000);
const int cs_minFormatValue = 0;
const int cs_maxFormatValue = 254;
#define MAKE_PRECISION_INFO(formatId, baseIndexMask, baseShiftCount) {formatId, baseIndexMask, 0x01 << baseShiftCount, MAKE_BASE_SEPARATION(baseShiftCount), 0.0f, 0.0f, 0.0f, 0.0f}
FormatPrecisionInfo s_formatPrecisionInfo[] =
{
MAKE_PRECISION_INFO(BINARY2(1111, 1110), BINARY2(0000, 0000), 0),
MAKE_PRECISION_INFO(BINARY2(1111, 1100), BINARY2(0000, 0001), 1),
MAKE_PRECISION_INFO(BINARY2(1111, 1000), BINARY2(0000, 0011), 2),
MAKE_PRECISION_INFO(BINARY2(1111, 0000), BINARY2(0000, 0111), 3),
MAKE_PRECISION_INFO(BINARY2(1110, 0000), BINARY2(0000, 1111), 4),
MAKE_PRECISION_INFO(BINARY2(1100, 0000), BINARY2(0001, 1111), 5),
MAKE_PRECISION_INFO(BINARY2(1000, 0000), BINARY2(0011, 1111), 6)
};
const int cs_minBaseShiftCount = 0;
const int cs_maxBaseShiftCount = static_cast<int>(sizeof(s_formatPrecisionInfo) / sizeof(s_formatPrecisionInfo[0])) - 1;
FormatData s_formatData[cs_maxFormatValue + 1];
bool s_installed;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int convertShiftToCount(int shift);
float calculateRange(int baseShiftCount);
void findClosestBase(int baseShiftCount, float midpoint, int &baseIndex, float &baseValue);
int findBaseShiftCountCoveringRange(float range);
bool findFormatForRange(int baseShiftCount, float minValue, float maxValue, uint8 &format);
uint32 doCompress(float w, float x, float y, float z, uint8 xFormat, uint8 yFormat, uint8 zFormat);
void doExpand(uint32 data, uint8 xFormat, uint8 yFormat, uint8 zFormat, float &w, float &x, float &y, float &z);
}
using namespace CompressedQuaternionNamespace;
// ======================================================================
// class CompressedQuaternionNamespace::FormatData
// ======================================================================
CompressedQuaternionNamespace::FormatData::FormatData() :
m_baseValue(0),
m_formatPrecisionIndex(0)
#ifdef _DEBUG
, m_installed(false)
#endif
{
}
// ----------------------------------------------------------------------
void CompressedQuaternionNamespace::FormatData::install(float baseValue, uint8 formatPrecisionIndex)
{
VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(cs_minBaseShiftCount, static_cast<int>(formatPrecisionIndex), cs_maxBaseShiftCount);
m_baseValue = baseValue;
m_formatPrecisionIndex = formatPrecisionIndex;
#ifdef _DEBUG
m_installed = true;
#endif
}
// ----------------------------------------------------------------------
uint32 CompressedQuaternionNamespace::FormatData::compressTenBit(float uncompressedValue) const
{
DEBUG_FATAL(!m_installed, ("format not installed."));
if (uncompressedValue >= m_baseValue)
{
const uint32 rawValue = static_cast<uint32>(s_formatPrecisionInfo[m_formatPrecisionIndex].compressFactorTenBit * std::max(0.0f, uncompressedValue - m_baseValue));
return std::min(cs_valueMaskTenBit, rawValue);
}
else
{
const uint32 rawValue = static_cast<uint32>(s_formatPrecisionInfo[m_formatPrecisionIndex].compressFactorTenBit * std::max(0.0f, m_baseValue - uncompressedValue));
return cs_signBitTenBit | std::min(cs_valueMaskTenBit, rawValue);
}
}
// ----------------------------------------------------------------------
uint32 CompressedQuaternionNamespace::FormatData::compressElevenBit(float uncompressedValue) const
{
DEBUG_FATAL(!m_installed, ("format not installed."));
if (uncompressedValue >= m_baseValue)
{
const uint32 rawValue = static_cast<uint32>(s_formatPrecisionInfo[m_formatPrecisionIndex].compressFactorElevenBit * std::max(0.0f, uncompressedValue - m_baseValue));
return std::min(cs_valueMaskElevenBit, rawValue);
}
else
{
const uint32 rawValue = static_cast<uint32>(s_formatPrecisionInfo[m_formatPrecisionIndex].compressFactorElevenBit * std::max(0.0f, m_baseValue - uncompressedValue));
return cs_signBitElevenBit | std::min(cs_valueMaskElevenBit, rawValue);
}
}
// ----------------------------------------------------------------------
// This function works properly with any kind of junk outside the lowest 10 bits. You do not need to mask the parameter prior to calling.
float CompressedQuaternionNamespace::FormatData::expandTenBit(uint32 compressedValue) const
{
DEBUG_FATAL(!m_installed, ("format not installed."));
if ((compressedValue & cs_signBitTenBit) != 0)
return m_baseValue - (static_cast<float>(compressedValue & cs_valueMaskTenBit) * s_formatPrecisionInfo[m_formatPrecisionIndex].expandFactorTenBit);
else
return m_baseValue + (static_cast<float>(compressedValue & cs_valueMaskTenBit) * s_formatPrecisionInfo[m_formatPrecisionIndex].expandFactorTenBit);
}
// ----------------------------------------------------------------------
// This function works properly with any kind of junk outside the lowest 11 bits. You do not need to mask the parameter prior to calling.
float CompressedQuaternionNamespace::FormatData::expandElevenBit(uint32 compressedValue) const
{
DEBUG_FATAL(!m_installed, ("format not installed."));
if ((compressedValue & cs_signBitElevenBit) != 0)
return m_baseValue - (static_cast<float>(compressedValue & cs_valueMaskElevenBit) * s_formatPrecisionInfo[m_formatPrecisionIndex].expandFactorElevenBit);
else
return m_baseValue + (static_cast<float>(compressedValue & cs_valueMaskElevenBit) * s_formatPrecisionInfo[m_formatPrecisionIndex].expandFactorElevenBit);
}
// ======================================================================
inline int CompressedQuaternionNamespace::convertShiftToCount(int shift)
{
VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, shift, 31);
return (0x01 << static_cast<uint8>(shift));
}
// ----------------------------------------------------------------------
inline float CompressedQuaternionNamespace::calculateRange(int baseShiftCount)
{
DEBUG_FATAL(baseShiftCount < 0, ("bad baseShiftCount arg [%d].", baseShiftCount));
return 4.0f / static_cast<float>(convertShiftToCount(baseShiftCount) + 1);
}
// ----------------------------------------------------------------------
void CompressedQuaternionNamespace::findClosestBase(int baseShiftCount, float midpoint, int &baseIndex, float &baseValue)
{
VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(cs_minBaseShiftCount, baseShiftCount, cs_maxBaseShiftCount);
//-- Brute force, this could be far more intelligent.
const int baseCount = s_formatPrecisionInfo[baseShiftCount].baseCount;
const float baseSeparation = s_formatPrecisionInfo[baseShiftCount].baseSeparation;
float closestBaseDistance = std::numeric_limits<float>::max();
float closestBaseValue = std::numeric_limits<float>::max();
int closestBaseIndex = -1;
for (int testBaseIndex = 0; testBaseIndex < baseCount; ++testBaseIndex)
{
const float testBaseValue = -1.0f + (testBaseIndex + 1) * baseSeparation;
const float testDistance = abs(testBaseValue - midpoint);
if (testDistance < closestBaseDistance)
{
closestBaseDistance = testDistance;
closestBaseValue = testBaseValue;
closestBaseIndex = testBaseIndex;
}
else
{
//-- We're getting farther away, stop now.
break;
}
}
baseIndex = closestBaseIndex;
baseValue = closestBaseValue;
}
// ----------------------------------------------------------------------
int CompressedQuaternionNamespace::findBaseShiftCountCoveringRange(float range)
{
for (int baseShiftCount = cs_maxBaseShiftCount; baseShiftCount >= 0; --baseShiftCount)
{
const float baseCountRange = calculateRange(baseShiftCount);
if (baseCountRange >= range)
{
//-- We found the tightest-fitting base count that is at least large enough to handle the specified range.
// We do this so that we have the greatest precision available over that tightest-fitting range.
return baseShiftCount;
}
}
DEBUG_FATAL(true, ("Failed to find a base count that handles the range [%g].", range));
return -1; //lint !e527 // unreachable // reachable in release.
}
// ----------------------------------------------------------------------
bool CompressedQuaternionNamespace::findFormatForRange(int baseShiftCount, float minValue, float maxValue, uint8 &format)
{
VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(cs_minBaseShiftCount, baseShiftCount, cs_maxBaseShiftCount);
DEBUG_FATAL(minValue > maxValue, ("minValue [%g] > maxValue [%g].", minValue, maxValue));
//-- Find the user range and midpoint.
const float range = maxValue - minValue;
const float midpoint = minValue + 0.5f * range;
//-- Find this format's closest base to the midpoint.
int baseIndex = -1;
float baseValue = 0.0f;
findClosestBase(baseShiftCount, midpoint, baseIndex, baseValue);
//-- Check if the user range fits within this format's base and range.
const float formatHalfRange = 0.5f * calculateRange(baseShiftCount);
const bool userRangeFitFormat = ((minValue >= (baseValue - formatHalfRange)) && (maxValue <= (baseValue + formatHalfRange)));
if (!userRangeFitFormat)
return false;
//-- Compute the format value from this information.
DEBUG_FATAL(static_cast<int>(s_formatPrecisionInfo[baseShiftCount].baseIndexMask & static_cast<uint8>(baseIndex)) != baseIndex, ("base index %d not valid for format with baseShift = %d.", baseIndex, baseShiftCount));
format = static_cast<uint8>(s_formatPrecisionInfo[baseShiftCount].formatId | static_cast<uint8>(baseIndex));
return true;
}
// ----------------------------------------------------------------------
uint32 CompressedQuaternionNamespace::doCompress(float w, float x, float y, float z, uint8 xFormat, uint8 yFormat, uint8 zFormat)
{
//-- Flip the quaternion if w is negative so we don't need to store a sign bit for w.
if (w < 0.0f)
{
w = -w;
x = -x;
y = -y;
z = -z;
}
//-- Ensure we are compressing a unit quaternion.
VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(-1.0f, x, 1.0f);
VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(-1.0f, y, 1.0f);
VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(-1.0f, z, 1.0f);
#ifdef _DEBUG
// If w is small enough, we won't be able to take the square root.
if (abs(w) >= cs_wAcceptableEpsilon)
{
const float calculatedW = sqrt(1.0f - (x*x + y*y + z*z));
DEBUG_FATAL(!WithinEpsilonInclusive(calculatedW, w, cs_wAcceptableEpsilon), ("Quaternion (w=%g,x=%g,y=%g,z=%g) does not appear to be a unit quaternion.", w, x, y, z));
}
#endif
//-- Pack the values.
const uint32 xPacked = s_formatData[xFormat].compressElevenBit(x);
const uint32 yPacked = s_formatData[yFormat].compressElevenBit(y);
const uint32 zPacked = s_formatData[zFormat].compressTenBit(z);
//-- Shift and combine.
return (xPacked << cs_xShift) | (yPacked << cs_yShift) | zPacked;
}
// ----------------------------------------------------------------------
void CompressedQuaternionNamespace::doExpand(uint32 data, uint8 xFormat, uint8 yFormat, uint8 zFormat, float &w, float &x, float &y, float &z)
{
//-- Expand the components.
x = s_formatData[xFormat].expandElevenBit(data >> cs_xShift);
y = s_formatData[yFormat].expandElevenBit(data >> cs_yShift);
z = s_formatData[zFormat].expandTenBit(data);
//-- Calculate w.
// @todo consider a faster square root approximation function.
w = sqrt(1.0f - (x*x + y*y + z*z));
}
// ======================================================================
// class CompressedQuaternion: static public member functions
// ======================================================================
void CompressedQuaternion::install()
{
//-- Calculate the data for quaternion (de)compression.
for (int baseShiftCount = 0; baseShiftCount <= cs_maxBaseShiftCount; ++baseShiftCount)
{
float const baseSeparation = s_formatPrecisionInfo[baseShiftCount].baseSeparation;
float const halfRange = 0.5f * calculateRange(baseShiftCount);
DEBUG_FATAL(halfRange <= 0.0f, ("bad half range [%g].", halfRange));
// compression factor is : uncompressedUnits * (total compressedUnits/ total uncompressedUnits) = compressedUnits
s_formatPrecisionInfo[baseShiftCount].compressFactorElevenBit = static_cast<float>(BINARY3(0011, 1111, 1111)) / halfRange;
s_formatPrecisionInfo[baseShiftCount].expandFactorElevenBit = halfRange / static_cast<float>(BINARY3(0011, 1111, 1111));
s_formatPrecisionInfo[baseShiftCount].compressFactorTenBit = static_cast<float>(BINARY3(0001, 1111, 1111)) / halfRange;
s_formatPrecisionInfo[baseShiftCount].expandFactorTenBit = halfRange / static_cast<float>(BINARY3(0001, 1111, 1111));
uint8 const formatId = s_formatPrecisionInfo[baseShiftCount].formatId;
int const baseCount = s_formatPrecisionInfo[baseShiftCount].baseCount;
VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, baseCount, cs_maxFormatValue);
for (int i = 0; i < baseCount; ++i)
{
uint8 const formatIndex = static_cast<uint8>(formatId | static_cast<uint8>(i));
float const baseValue = - 1.0f + (i + 1) * baseSeparation;
VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(0, static_cast<int>(formatIndex), cs_maxFormatValue);
s_formatData[formatIndex].install(baseValue, static_cast<uint8>(baseShiftCount));
}
}
s_installed = true;
}
// ----------------------------------------------------------------------
/**
* Determine the most precise compression format for a quaternion component
* that will cover the specified range of value.
*
* Our quaternion compression mechanism uses a fixed number of output bits
* to represent a component of a quaternion. We let the level of precision
* vary based on the range of values that the quaternion component needs to
* represent over time.
*
* The caller should do something like this. For each quaternion component
* that is to be compressed, find the range of values that the component takes
* on across the quaternions that will be compressed with the same compression
* format. Feed the min and max value into this function, then store the
* returned format to be used during compression and decompression for that
* particular component. This needs to be done for the x, y and z components,
* but not the w component. We calculate the w component from the x, y and z.
* We can do this because we are using unit quaternions.
*/
uint8 CompressedQuaternion::getOptimalCompressionFormat(float minValue, float maxValue)
{
DEBUG_FATAL(minValue > maxValue, ("min and max are not set properly."));
//-- Find the largest division count (= highest precision compressed representation)
// that can represent values over the specified range.
int baseShiftCount = findBaseShiftCountCoveringRange(maxValue - minValue);
uint8 format = 255;
for (; (baseShiftCount > -1) && !findFormatForRange(baseShiftCount, minValue, maxValue, format); --baseShiftCount)
{
}
DEBUG_FATAL(baseShiftCount < 0, ("failed to find an encoding for range [%g, %g].", minValue, maxValue));
VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(cs_minFormatValue, static_cast<int>(format), cs_maxFormatValue);
return format;
}
// ----------------------------------------------------------------------
/**
* Find optimal compression format for each x, y and z component of the
* specified source rotations.
*/
void CompressedQuaternion::getOptimalCompressionFormat(const QuaternionVector &sourceRotations, uint8 &xFormat, uint8 &yFormat, uint8 &zFormat)
{
//-- Handle no source rotations.
if (sourceRotations.empty())
{
DEBUG_WARNING(true, ("getOptimalCompressionFormat(): sourceRotations container is empty, returning least precise format."));
// Return least precise format because that is the only thing guaranteed to cover na
xFormat = s_formatPrecisionInfo[0].formatId;
yFormat = s_formatPrecisionInfo[0].formatId;
zFormat = s_formatPrecisionInfo[0].formatId;
return;
}
//-- Collect min and max component values for the rotations.
float minX = std::numeric_limits<float>::max();
float maxX = -std::numeric_limits<float>::max();
float minY = std::numeric_limits<float>::max();
float maxY = -std::numeric_limits<float>::max();
float minZ = std::numeric_limits<float>::max();
float maxZ = -std::numeric_limits<float>::max();
const QuaternionVector::const_iterator endIt = sourceRotations.end();
for (QuaternionVector::const_iterator it = sourceRotations.begin(); it != endIt; ++it)
{
// Get the quaternion.
Quaternion rotation = *it;
// Flip quaternion if w < 0.
if (rotation.w < 0.0f)
{
rotation.x = -rotation.x;
rotation.y = -rotation.y;
rotation.z = -rotation.z;
}
// Update the min and max component values.
minX = std::min(minX, rotation.x);
maxX = std::max(maxX, rotation.x);
minY = std::min(minY, rotation.y);
maxY = std::max(maxY, rotation.y);
minZ = std::min(minZ, rotation.z);
maxZ = std::max(maxZ, rotation.z);
}
xFormat = getOptimalCompressionFormat(minX, maxX);
yFormat = getOptimalCompressionFormat(minY, maxY);
zFormat = getOptimalCompressionFormat(minZ, maxZ);
}
// ----------------------------------------------------------------------
void CompressedQuaternion::compressRotations(const QuaternionVector &sourceRotations, uint8 xFormat, uint8 yFormat, uint8 zFormat, CompressedQuaternionVector &compressedRotations)
{
//-- Adjust destination vector size.
compressedRotations.clear();
compressedRotations.reserve(sourceRotations.size());
//-- Convert each source rotation to a destination rotation.
const QuaternionVector::const_iterator endIt = sourceRotations.end();
for (QuaternionVector::const_iterator it = sourceRotations.begin(); it != endIt; ++it)
{
compressedRotations.push_back(CompressedQuaternion(*it, xFormat, yFormat, zFormat));
#if VERIFY_COMPRESSION
const CompressedQuaternion &compressedRotation = compressedRotations.back();
const Quaternion expandedRotation = compressedRotation.expand(xFormat, yFormat, zFormat);
Quaternion sourceRotation = *it;
if (sourceRotation.w < 0.0f)
{
sourceRotation.w = -sourceRotation.w;
sourceRotation.x = -sourceRotation.x;
sourceRotation.y = -sourceRotation.y;
sourceRotation.z = -sourceRotation.z;
}
const float deltaW = abs(expandedRotation.w - sourceRotation.w);
const float deltaX = abs(expandedRotation.x - sourceRotation.x);
const float deltaY = abs(expandedRotation.y - sourceRotation.y);
const float deltaZ = abs(expandedRotation.z - sourceRotation.z);
if ( (deltaW > cs_wAcceptableEpsilon) ||
(deltaX > cs_xAcceptableEpsilon) ||
(deltaY > cs_yAcceptableEpsilon) ||
(deltaZ > cs_zAcceptableEpsilon))
{
//-- Let's do it again. Make it easier to debug.
const CompressedQuaternion cq2(sourceRotation, xFormat, yFormat, zFormat);
const Quaternion eq2 = cq2.expand(xFormat, yFormat, zFormat);
UNREF(cq2);
UNREF(eq2);
DEBUG_FATAL(true, ("compression data distortion. [source=(%g,%g,%g,%g),dest=(%g,%g,%g,%g)].",
sourceRotation.w, sourceRotation.x, sourceRotation.y, sourceRotation.z,
expandedRotation.w, expandedRotation.x, expandedRotation.y, expandedRotation.z));
}
#endif
}
}
// ======================================================================
CompressedQuaternion::CompressedQuaternion(uint32 compressedValue) :
m_data(compressedValue)
{
}
// ----------------------------------------------------------------------
CompressedQuaternion::CompressedQuaternion(const Quaternion &rhs, uint8 xFormat, uint8 yFormat, uint8 zFormat) :
m_data(doCompress(rhs.w, rhs.x, rhs.y, rhs.z, xFormat, yFormat, zFormat))
{
}
// ----------------------------------------------------------------------
CompressedQuaternion::CompressedQuaternion(float w, float x, float y, float z, uint8 xFormat, uint8 yFormat, uint8 zFormat) :
m_data(doCompress(w, x, y, z, xFormat, yFormat, zFormat))
{
}
// ----------------------------------------------------------------------
Quaternion CompressedQuaternion::expand(uint8 xFormat, uint8 yFormat, uint8 zFormat) const
{
float w;
float x;
float y;
float z;
doExpand(m_data, xFormat, yFormat, zFormat, w, x, y, z);
return Quaternion(w, x, y, z);
}
// ----------------------------------------------------------------------
void CompressedQuaternion::expand(uint8 xFormat, uint8 yFormat, uint8 zFormat, Quaternion &destination) const
{
doExpand(m_data, xFormat, yFormat, zFormat, destination.w, destination.x, destination.y, destination.z);
}
// ----------------------------------------------------------------------
void CompressedQuaternion::expand(uint8 xFormat, uint8 yFormat, uint8 zFormat, float &w, float &x, float &y, float &z) const
{
doExpand(m_data, xFormat, yFormat, zFormat, w, x, y, z);
}
// ----------------------------------------------------------------------
uint32 CompressedQuaternion::getCompressedValue() const
{
return m_data;
}
// ----------------------------------------------------------------------
void CompressedQuaternion::debugDump() const
{
DEBUG_REPORT_LOG(true, ("[data=0x%08x]\n", static_cast<unsigned int>(m_data)));
}
// ======================================================================
@@ -0,0 +1,56 @@
// ======================================================================
//
// CompressedQuaternion.h
// Copyright 2002 Sony Online Entertainment, Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_CompressedQuaternion_H
#define INCLUDED_CompressedQuaternion_H
// ======================================================================
class Quaternion;
// ======================================================================
class CompressedQuaternion
{
public:
typedef stdvector<Quaternion>::fwd QuaternionVector;
typedef stdvector<CompressedQuaternion>::fwd CompressedQuaternionVector;
public:
static void install();
static uint8 getOptimalCompressionFormat(float minValue, float maxValue);
static void getOptimalCompressionFormat(const QuaternionVector &sourceRotations, uint8 &xFormat, uint8 &yFormat, uint8 &zFormat);
static void compressRotations(const QuaternionVector &sourceRotations, uint8 xFormat, uint8 yFormat, uint8 zFormat, CompressedQuaternionVector &compressedRotations);
public:
explicit CompressedQuaternion(uint32 compressedValue);
CompressedQuaternion(const Quaternion &rhs, uint8 xFormat, uint8 yFormat, uint8 zFormat);
CompressedQuaternion(float w, float x, float y, float z, uint8 xFormat, uint8 yFormat, uint8 zFormat);
Quaternion expand(uint8 xFormat, uint8 yFormat, uint8 zFormat) const;
void expand(uint8 xFormat, uint8 yFormat, uint8 zFormat, Quaternion &destination) const;
void expand(uint8 xFormat, uint8 yFormat, uint8 zFormat, float &w, float &x, float &y, float &z) const;
uint32 getCompressedValue() const;
void debugDump() const;
private:
uint32 m_data;
};
// ======================================================================
#endif
@@ -0,0 +1,42 @@
// ======================================================================
//
// ConfigSharedMath.cpp
// copyright 2004 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/ConfigSharedMath.h"
#include "sharedFoundation/ConfigFile.h"
// ======================================================================
#define KEY_BOOL(a,b) (ms_ ## a = ConfigFile::getKeyBool("SharedMath", #a, (b)))
// ======================================================================
namespace ConfigSharedMathNamespace
{
bool ms_reportRangeLoopWarnings;
}
using namespace ConfigSharedMathNamespace;
// ======================================================================
void ConfigSharedMath::install()
{
KEY_BOOL(reportRangeLoopWarnings, false);
}
// ----------------------------------------------------------------------
bool ConfigSharedMath::getReportRangeLoopWarnings()
{
return ms_reportRangeLoopWarnings;
}
// ======================================================================
@@ -0,0 +1,24 @@
// ======================================================================
//
// ConfigSharedMath.h
// Copyright 2004, Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_ConfigSharedMath_H
#define INCLUDED_ConfigSharedMath_H
// ======================================================================
class ConfigSharedMath
{
public:
static void install();
static bool getReportRangeLoopWarnings();
};
// ======================================================================
#endif
@@ -0,0 +1,18 @@
// ======================================================================
//
// FirstMath.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_FirstMath_H
#define INCLUDED_FirstMath_H
// ======================================================================
#include "sharedFoundation/FirstSharedFoundation.h"
// ======================================================================
#endif
@@ -0,0 +1,398 @@
// ======================================================================
//
// IndexedTriangleList.cpp
// Copyright 2001 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/IndexedTriangleList.h"
#include "sharedFile/Iff.h"
#include "sharedMath/Plane.h"
#include "sharedMath/Vector.h"
#include <vector>
#include <limits>
// ======================================================================
const Tag TAG_IDTL = TAG(I,D,T,L);
const Tag TAG_VERT = TAG(V,E,R,T);
const Tag TAG_INDX = TAG(I,N,D,X);
// ======================================================================
IndexedTriangleList::IndexedTriangleList() :
m_mergeVertices(false),
m_epsilon(0.0f),
m_vertices(new std::vector<Vector>),
m_indices(new std::vector<int>)
{
}
// ----------------------------------------------------------------------
IndexedTriangleList::IndexedTriangleList(Iff & iff) :
m_mergeVertices(false),
m_epsilon(0.0f),
m_vertices(new std::vector<Vector>),
m_indices(new std::vector<int>)
{
load(iff);
}
// ----------------------------------------------------------------------
IndexedTriangleList::~IndexedTriangleList()
{
delete m_vertices;
delete m_indices;
}
// ----------------------------------------------------------------------
const std::vector<Vector> &IndexedTriangleList::getVertices() const
{
return *m_vertices;
}
// ----------
const std::vector<int> &IndexedTriangleList::getIndices() const
{
return *m_indices;
}
// ----------------------------------------------------------------------
std::vector<Vector> &IndexedTriangleList::getVertices()
{
return *m_vertices;
}
// ----------
std::vector<int> &IndexedTriangleList::getIndices()
{
return *m_indices;
}
// ----------------------------------------------------------------------
void IndexedTriangleList::load(Iff &iff)
{
clear();
iff.enterForm(TAG_IDTL);
switch (iff.getCurrentName())
{
case TAG_0000:
load_0000(iff);
break;
default:
{
char buffer[512];
iff.formatLocation(buffer, sizeof(buffer));
DEBUG_FATAL(true, ("Unknown version number %s", buffer));
}
}
iff.exitForm(TAG_IDTL);
}
// ----------------------------------------------------------------------
void IndexedTriangleList::load_0000(Iff &iff)
{
iff.enterForm(TAG_0000);
iff.enterChunk(TAG_VERT);
{
const uint numberOfVertices = static_cast<uint>( iff.getChunkLengthLeft(3 * sizeof(float)) );
DEBUG_FATAL(!numberOfVertices, ("No vertices"));
m_vertices->resize(numberOfVertices);
iff.read_floatVector( static_cast<int>(numberOfVertices), &(*m_vertices)[0]);
}
iff.exitChunk(TAG_VERT);
iff.enterChunk(TAG_INDX);
{
const uint numberOfIndices = static_cast<uint>( iff.getChunkLengthLeft(sizeof(int32)) );
DEBUG_FATAL(!numberOfIndices, ("No indices"));
m_indices->resize(numberOfIndices);
for (uint i = 0; i < numberOfIndices; ++i)
(*m_indices)[i] = iff.read_int32();
}
iff.exitChunk(TAG_INDX);
iff.exitForm(TAG_0000);
}
// ----------------------------------------------------------------------
void IndexedTriangleList::write(Iff &iff) const
{
iff.insertForm(TAG_IDTL);
iff.insertForm(TAG_0000);
iff.insertChunk(TAG_VERT);
{
const uint numberOfVertices = m_vertices->size();
for (uint i = 0; i < numberOfVertices; ++i)
iff.insertChunkFloatVector((*m_vertices)[i]);
}
iff.exitChunk(TAG_VERT);
iff.insertChunk(TAG_INDX);
{
const uint numberOfIndices = m_indices->size();
for (uint i = 0; i < numberOfIndices; ++i)
iff.insertChunkData(static_cast<int32>((*m_indices)[i]));
}
iff.exitChunk(TAG_INDX);
iff.exitForm(TAG_0000);
iff.exitForm(TAG_IDTL);
}
// ----------------------------------------------------------------------
void IndexedTriangleList::clear()
{
m_vertices->clear();
m_indices->clear();
}
// ----------------------------------------------------------------------
void IndexedTriangleList::addVertices(const Vector *vertices, int numberOfVertices, std::vector<int> &indices)
{
indices.reserve( static_cast<uint>(numberOfVertices) );
if (m_mergeVertices)
{
for (int i = 0; i < numberOfVertices; ++i)
{
// look for a matching vertex
uint j = 0;
for ( ; j < m_vertices->size() && vertices[i] != (*m_vertices)[j] && vertices[i].magnitudeBetween((*m_vertices)[j]) > m_epsilon; ++j)
{}
if (j >= m_vertices->size())
{
indices.push_back(static_cast<int>(m_vertices->size()));
m_vertices->push_back(vertices[i]);
}
else
indices.push_back( static_cast<int>(j) );
}
}
else
{
for (int i = 0; i < numberOfVertices; ++i)
{
indices.push_back(static_cast<int>(m_vertices->size()));
m_vertices->push_back(vertices[i]);
}
}
}
// ----------------------------------------------------------------------
void IndexedTriangleList::addTriangleList(const Vector *vertices, int numberOfVertices)
{
DEBUG_FATAL(numberOfVertices < 3 || numberOfVertices % 3 != 0, ("Invalid number of vertices for a triangle list %d", numberOfVertices));
std::vector<int> vertexIndices;
addVertices(vertices, numberOfVertices, vertexIndices);
for (uint i = 0; i < static_cast<uint>(numberOfVertices); ++i)
m_indices->push_back(vertexIndices[i]);
}
// ----------------------------------------------------------------------
void IndexedTriangleList::addTriangleStrip(const Vector *vertices, int numberOfVertices)
{
DEBUG_FATAL(numberOfVertices < 3, ("Invalid number of vertices for a triangle strip %d", numberOfVertices));
std::vector<int> vertexIndices;
addVertices(vertices, numberOfVertices, vertexIndices);
const uint triangleCount = static_cast<uint>(numberOfVertices) - 2;
for (uint i = 0; i < triangleCount; ++i)
if (i & 1)
{
m_indices->push_back(vertexIndices[i+0]);
m_indices->push_back(vertexIndices[i+2]);
m_indices->push_back(vertexIndices[i+1]);
}
else
{
m_indices->push_back(vertexIndices[i+0]);
m_indices->push_back(vertexIndices[i+1]);
m_indices->push_back(vertexIndices[i+2]);
}
}
// ----------------------------------------------------------------------
void IndexedTriangleList::addTriangleFan(const Vector *vertices, int numberOfVertices)
{
DEBUG_FATAL(numberOfVertices < 3, ("Invalid number of vertices for a triangle fan %d", numberOfVertices));
std::vector<int> vertexIndices;
addVertices(vertices, numberOfVertices, vertexIndices);
const uint triangleCount = static_cast<uint>(numberOfVertices) - 2;
for (uint i = 0; i < triangleCount; ++i)
{
m_indices->push_back(vertexIndices[0]);
m_indices->push_back(vertexIndices[i+1]);
m_indices->push_back(vertexIndices[i+2]);
}
}
// ----------------------------------------------------------------------
void IndexedTriangleList::addIndexedTriangleList(const Vector *vertices, int numberOfVertices, const int *indices, int numberOfIndices)
{
DEBUG_FATAL(numberOfVertices < 3, ("Invalid number of vertices for an indexed triangle list %d", numberOfVertices));
DEBUG_FATAL(numberOfIndices < 3 || numberOfIndices % 3 != 0, ("Invalid number of indices for an indexed triangle list %d", numberOfIndices));
std::vector<int> vertexIndices;
addVertices(vertices, numberOfVertices, vertexIndices);
for (uint i = 0; i < static_cast<uint>(numberOfIndices); ++i)
{
uint index = static_cast<uint>(indices[i]);
m_indices->push_back(vertexIndices[index]);
}
}
// ----------------------------------------------------------------------
void IndexedTriangleList::addIndexedTriangleStrip(const Vector *vertices, int numberOfVertices, const int *indices, int numberOfIndices)
{
DEBUG_FATAL(numberOfVertices < 3, ("Invalid number of vertices for an indexed triangle list %d", numberOfVertices));
DEBUG_FATAL(numberOfIndices < 3, ("Invalid number of indices for an indexed triangle strip %d", numberOfIndices));
std::vector<int> vertexIndices;
addVertices(vertices, numberOfVertices, vertexIndices);
const uint triangleCount = static_cast<uint>(numberOfIndices) - 2;
for (uint i = 0; i < triangleCount; ++i)
{
if (i & 1)
{
m_indices->push_back(vertexIndices[ static_cast<uint>(indices[i+0]) ]);
m_indices->push_back(vertexIndices[ static_cast<uint>(indices[i+2]) ]);
m_indices->push_back(vertexIndices[ static_cast<uint>(indices[i+1]) ]);
}
else
{
m_indices->push_back(vertexIndices[ static_cast<uint>(indices[i+0]) ]);
m_indices->push_back(vertexIndices[ static_cast<uint>(indices[i+1]) ]);
m_indices->push_back(vertexIndices[ static_cast<uint>(indices[i+2]) ]);
}
}
}
// ----------------------------------------------------------------------
void IndexedTriangleList::addIndexedTriangleFan(const Vector *vertices, int numberOfVertices, const int *indices, int numberOfIndices)
{
DEBUG_FATAL(numberOfVertices < 3, ("Invalid number of vertices for an indexed triangle list %d", numberOfVertices));
DEBUG_FATAL(numberOfIndices < 3, ("Invalid number of indices for an indexed triangle fan %d", numberOfIndices));
std::vector<int> vertexIndices;
addVertices(vertices, numberOfVertices, vertexIndices);
const uint triangleCount = static_cast<uint>(numberOfIndices) - 2;
for (uint i = 0; i < triangleCount; ++i)
{
m_indices->push_back(vertexIndices[ static_cast<uint>(indices[0])]);
m_indices->push_back(vertexIndices[ static_cast<uint>(indices[i+1])]);
m_indices->push_back(vertexIndices[ static_cast<uint>(indices[i+2])]);
}
}
// ----------------------------------------------------------------------
IndexedTriangleList * IndexedTriangleList::clone() const
{
IndexedTriangleList * const indexedTriangleList = new IndexedTriangleList();
indexedTriangleList->copy(this);
return indexedTriangleList;
}
// ----------------------------------------------------------------------
void IndexedTriangleList::copy(IndexedTriangleList const * const indexedTriangleList)
{
m_mergeVertices = indexedTriangleList->m_mergeVertices;
m_epsilon = indexedTriangleList->m_epsilon;
*m_vertices = *indexedTriangleList->m_vertices;
*m_indices = *indexedTriangleList->m_indices;
}
// ----------------------------------------------------------------------
bool IndexedTriangleList::collide(Vector const & start, Vector const & end, Vector & result) const
{
return collide(start, end, *m_indices, result);
}
// ----------------------------------------------------------------------
bool IndexedTriangleList::collide(Vector const & start, Vector const & end, std::vector<int> const & indices, Vector & result) const
{
bool found = false;
Vector shortenedEnd(end);
Vector const direction(end - start);
Vector normal;
Plane plane;
Vector intersection;
std::vector<Vector> const & vertices = *m_vertices;
uint const numberOfIndices = indices.size();
for (int index = 0; static_cast<int>(numberOfIndices - index) >= 3; /*increment in body*/)
{
Vector const & v0 = vertices[indices[index++]];
Vector const & v1 = vertices[indices[index++]];
Vector const & v2 = vertices[indices[index++]];
//-- Compute normal
normal = (v0 - v2).cross(v1 - v0);
//-- Ignore backfaces. (Use float min to prevent precision errors.)
if (direction.dot(normal) < std::numeric_limits<float>::min())
{
//-- It doesn't matter that the normal is not normalized
plane.set(normal, v0);
//-- See if the end points intersect the plane the polygon lies on, lies within the polygon, and is closer to start than the previous point
if ((plane.findDirectedIntersection(start, shortenedEnd, intersection)) &&
(start.magnitudeBetweenSquared(intersection) < start.magnitudeBetweenSquared(shortenedEnd)) &&
(intersection.inPolygon(v0, v1, v2)))
{
found = true;
result = intersection;
shortenedEnd = intersection;
}
}
}
return found;
}
// ======================================================================
@@ -0,0 +1,89 @@
// ======================================================================
//
// IndexedTriangleList.h
// Copyright 2001 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_IndexedTriangleList_H
#define INCLUDED_IndexedTriangleList_H
// ======================================================================
class Iff;
class Vector;
// ======================================================================
class IndexedTriangleList
{
public:
IndexedTriangleList();
explicit IndexedTriangleList(Iff &iff);
~IndexedTriangleList();
const stdvector<Vector>::fwd &getVertices() const;
const stdvector<int>::fwd &getIndices() const;
stdvector<Vector>::fwd &getVertices();
stdvector<int>::fwd &getIndices();
void load(Iff &iff);
void write(Iff &iff) const;
void allowVertexMerging(bool mergeVertices);
void setVertexMergeEpsilon(float epsilon);
void clear();
void addTriangleList(const Vector *vertices, int numberOfVertices);
void addTriangleStrip(const Vector *vertices, int numberOfVertices);
void addTriangleFan(const Vector *vertices, int numberOfVertices);
void addIndexedTriangleList(const Vector *vertices, int numberOfVertices, const int *indices, int numberOfIndices);
void addIndexedTriangleStrip(const Vector *vertices, int numberOfVertices, const int *indices, int numberOfIndices);
void addIndexedTriangleFan(const Vector *vertices, int numberOfVertices, const int *indices, int numberOfIndices);
IndexedTriangleList* clone() const;
void copy(const IndexedTriangleList *tris);
bool collide(Vector const & start, Vector const & end, Vector & result) const;
bool collide(Vector const & start, Vector const & end, stdvector<int>::fwd const & indices, Vector & result) const;
private:
// disabled
IndexedTriangleList(const IndexedTriangleList &);
IndexedTriangleList &operator =(const IndexedTriangleList &);
private:
void load_0000(Iff &iff);
void addVertices(const Vector *vertices, int numberOfVertices, stdvector<int>::fwd &indices);
private:
bool m_mergeVertices;
float m_epsilon;
stdvector<Vector>::fwd * const m_vertices;
stdvector<int>::fwd * const m_indices;
};
// ======================================================================
inline void IndexedTriangleList::allowVertexMerging(bool mergeVertices)
{
m_mergeVertices = mergeVertices;
}
// ----------------------------------------------------------------------
inline void IndexedTriangleList::setVertexMergeEpsilon(float epsilon)
{
m_epsilon = epsilon;
}
// ======================================================================
#endif
@@ -0,0 +1,156 @@
//===================================================================
//
// Line2d.h
// asommers
//
// copyright 2001, sony online entertainment
//
//===================================================================
#ifndef INCLUDED_Line2d_H
#define INCLUDED_Line2d_H
//===================================================================
#include "Vector2d.h"
//===================================================================
class Line2d
{
private:
Vector2d m_normal;
float m_c;
public:
Line2d ();
Line2d (float x0, float y0, float x1, float y1);
Line2d (const Vector2d& normal, float c);
Line2d (const Vector2d& point0, const Vector2d& point1);
void set (const Vector2d& normal, float c);
void set (const Vector2d& point0, const Vector2d& point1);
const Vector2d& getNormal () const;
const float getC () const;
float computeDistanceTo (const Vector2d& point) const;
const Vector2d project (const Vector2d& point) const;
bool findIntersection(Vector2d const & point0, Vector2d const & point1, Vector2d & intersection) const;
};
//===================================================================
inline Line2d::Line2d () :
m_normal (1.f, 0.f),
m_c (0.f)
{
}
//-------------------------------------------------------------------
inline Line2d::Line2d (float const x0, float const y0, float const x1, float const y1) :
m_normal(),
m_c(0.f)
{
set(Vector2d(x0, y0), Vector2d(x1, y1));
}
//-------------------------------------------------------------------
inline Line2d::Line2d (const Vector2d& normal, float c) :
m_normal (normal),
m_c (c)
{
}
//-------------------------------------------------------------------
inline Line2d::Line2d (const Vector2d& point0, const Vector2d& point1) :
m_normal (),
m_c (0.f)
{
set (point0, point1);
}
//-------------------------------------------------------------------
inline void Line2d::set (const Vector2d& normal, float c)
{
m_normal = normal;
m_c = c;
}
//-------------------------------------------------------------------
inline void Line2d::set (const Vector2d& point0, const Vector2d& point1)
{
m_normal.set (-point1.y + point0.y, point1.x - point0.x);
if (!m_normal.normalize ())
{
m_normal.set (1.f, 0.f);
DEBUG_FATAL (true, ("Line::set could not normalize vector"));
}
m_c = -m_normal.dot (point0);
}
//-------------------------------------------------------------------
inline const Vector2d& Line2d::getNormal () const
{
return m_normal;
}
//-------------------------------------------------------------------
inline const float Line2d::getC () const
{
return m_c;
}
//-------------------------------------------------------------------
inline float Line2d::computeDistanceTo (const Vector2d& point) const
{
return m_normal.dot (point) + m_c;
}
//-------------------------------------------------------------------
inline const Vector2d Line2d::project (const Vector2d& point) const
{
return point - (m_normal * computeDistanceTo (point));
}
//-------------------------------------------------------------------
inline bool Line2d::findIntersection(Vector2d const & start, Vector2d const & end, Vector2d & intersection) const
{
float const t0(computeDistanceTo(start));
float const t1(computeDistanceTo(end));
// check to make sure the endpoints span the plane
if ((t0 * t1) > 0.f)
return false;
// both zero
if (t0 == t1)
{
intersection = start;
return true;
}
// safe since sign of t0 is always opposite t1
float const t = t0 / (t0 - t1);
intersection.x = start.x + (end.x - start.x) * t;
intersection.y = start.y + (end.y - start.y) * t;
return true;
}
//===================================================================
#endif
@@ -0,0 +1,520 @@
// ======================================================================
//
// MxCifQuadTree.cpp
//
// Copyright 2002, Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/MxCifQuadTree.h"
#include "sharedMath/MxCifQuadTreeBounds.h"
//==============================================================================
/**
* Class constructor.
*
* @param minX min x coordinate of our area
* @param minY min y coordinate of our area
* @param maxX max x coordinate of our area
* @param maxY max y coordinate of our area
* @param maxDepth max depth of this tree
*/
MxCifQuadTree::MxCifQuadTree(float minX, float minY, float maxX, float maxY, int maxDepth) :
m_minX(minX),
m_minY(minY),
m_maxX(maxX),
m_maxY(maxY),
m_centerX((m_maxX - m_minX) / 2.0f + m_minX),
m_centerY((m_maxY - m_minY) / 2.0f + m_minY),
m_maxDepth(maxDepth),
m_urTree(NULL),
m_ulTree(NULL),
m_llTree(NULL),
m_lrTree(NULL),
m_xAxisTree(minX, maxX, maxDepth),
m_yAxisTree(minY, maxY, maxDepth)
{
} // MxCifQuadTree::MxCifQuadTree
//------------------------------------------------------------------------------
/**
* Class destructor.
*/
MxCifQuadTree::~MxCifQuadTree()
{
delete m_urTree;
m_urTree = NULL;
delete m_ulTree;
m_ulTree = NULL;
delete m_llTree;
m_llTree = NULL;
delete m_lrTree;
m_lrTree = NULL;
} // MxCifQuadTree::~MxCifQuadTree
//------------------------------------------------------------------------------
/**
* Splits this quad into four sub-quads.
*
* @return true if we split, false if we have reaced the max depth
*/
bool MxCifQuadTree::split(void)
{
if (m_maxDepth <= 1)
return false;
int newDepth = m_maxDepth - 1;
m_urTree = new MxCifQuadTree(m_centerX, m_centerY, m_maxX, m_maxY, newDepth);
m_ulTree = new MxCifQuadTree( m_minX, m_centerY, m_centerX, m_maxY, newDepth);
m_llTree = new MxCifQuadTree( m_minX, m_minY, m_centerX, m_centerY, newDepth);
m_lrTree = new MxCifQuadTree(m_centerX, m_minY, m_maxX, m_centerY, newDepth);
return true;
} // MxCifQuadTree::split
//------------------------------------------------------------------------------
/**
* Adds an object to the tree.
*
* @param object the object to add
*
* @return true if the object was added, false if not
*/
bool MxCifQuadTree::addObject(const MxCifQuadTreeBounds & object)
{
// see if the object fits entirely within us
if (object.getMaxX() <= m_maxX &&
object.getMaxY() <= m_maxY &&
object.getMinX() >= m_minX &&
object.getMinY() >= m_minY)
{
// try putting the object in a child node
if (m_maxDepth > 1)
{
if (m_urTree == NULL)
{
if (!split())
return false;
}
if (m_urTree->addObject(object) ||
m_ulTree->addObject(object) ||
m_llTree->addObject(object) ||
m_lrTree->addObject(object))
{
return true;
}
// put the object into one of the axis trees
if (object.getMaxX() < m_centerX ||
object.getMinX() > m_centerX)
{
// add the object to our x-axis tree
m_xAxisTree.addObject(object);
}
else
{
// add the object to our y-axis tree
m_yAxisTree.addObject(object);
}
return true;
}
else
{
// can't subdivide further, add the object to our list
if (object.getMaxX() - object.getMinX() < object.getMaxY() - object.getMinY())
m_xAxisTree.addObject(object);
else
m_yAxisTree.addObject(object);
return true;
}
}
else
return false;
} // MxCifQuadTree::addObject
//------------------------------------------------------------------------------
/**
* Removes an object from the tree.
*
* @param object the object to remove
*
* @return true if the object was removed, false if not
*/
bool MxCifQuadTree::removeObject(const MxCifQuadTreeBounds & object)
{
// see if the object fits entirely within us
if (object.getMaxX() <= m_maxX &&
object.getMaxY() <= m_maxY &&
object.getMinX() >= m_minX &&
object.getMinY() >= m_minY)
{
if (m_maxDepth > 1)
{
if (m_urTree != NULL)
{
// check if the object is in a sub-node
if (m_urTree->removeObject(object) ||
m_ulTree->removeObject(object) ||
m_llTree->removeObject(object) ||
m_lrTree->removeObject(object))
{
return true;
}
}
// remove the object from one of the axis trees
if (object.getMaxX() < m_centerX ||
object.getMinX() > m_centerX)
{
return m_xAxisTree.removeObject(object);
}
else
{
return m_yAxisTree.removeObject(object);
}
}
else
{
// can't subdivide further, remove the object from an axis tree
if (object.getMaxX() - object.getMinX() < object.getMaxY() - object.getMinY())
return m_xAxisTree.removeObject(object);
else
return m_yAxisTree.removeObject(object);
}
}
else
return false;
} // MxCifQuadTree::removeObject
//------------------------------------------------------------------------------
/**
* Finds all the objects that contain a given point.
*
* @param x x coordinate of the point
* @param y y coordinate of the point
* @param objects vector that will be filled in with the objects that contain the point
*/
void MxCifQuadTree::getObjectsAt(float x, float y,
std::vector<const MxCifQuadTreeBounds *> & objects) const
{
// find if we contain the point
if (x <= m_maxX &&
x >= m_minX &&
y <= m_maxY &&
y >= m_minY)
{
// if we have sub-trees, pass the point to the tree that contains it
if (m_urTree != NULL)
{
if (x >= m_centerX && y >= m_centerY)
m_urTree->getObjectsAt(x, y, objects);
else if (x <= m_centerX && y >= m_centerY)
m_ulTree->getObjectsAt(x, y, objects);
else if (x <= m_centerX && y <= m_centerY)
m_llTree->getObjectsAt(x, y, objects);
else
m_lrTree->getObjectsAt(x, y, objects);
}
// test the objects in our axis trees
m_xAxisTree.getObjectsAt(x, y, objects);
m_yAxisTree.getObjectsAt(x, y, objects);
}
} // MxCifQuadTree::getObjectsAt
//------------------------------------------------------------------------------
/**
* Returns all the objects in the tree.
*
* @param objects vector that will be filled in with the objects
*/
void MxCifQuadTree::getAllObjects(std::vector<const MxCifQuadTreeBounds *> & objects) const
{
// if we have sub-trees, pass the point to the tree that contains it
if (m_urTree != NULL)
{
m_urTree->getAllObjects(objects);
m_ulTree->getAllObjects(objects);
m_llTree->getAllObjects(objects);
m_lrTree->getAllObjects(objects);
}
m_xAxisTree.getAllObjects(objects);
m_yAxisTree.getAllObjects(objects);
} // MxCifQuadTree::getAllObjects
//==============================================================================
/**
* Class constructor.
*
* @param min min range value
* @param min max range value
* @param maxDepth max depth of this tree
*/
MxCifQuadTree::MxCifBinTree::MxCifBinTree(float min, float max, int maxDepth) :
m_min(min),
m_max(max),
m_center((max - min) / 2.0f + min),
m_maxDepth(maxDepth),
m_left(NULL),
m_right(NULL),
m_objects()
{
} // MxCifBinTree::MxCifBinTree
/**
* Class destructor.
*/
MxCifQuadTree::MxCifBinTree::~MxCifBinTree()
{
delete m_left;
m_left = NULL;
delete m_right;
m_right = NULL;
m_objects.clear();
} // MxCifBinTree::~MxCifBinTree
/**
* Splits this tree into two sub-trees.
*
* @return true if we split, false if we have reaced the max depth
*/
bool MxCifQuadTree::MxCifBinTree::split(void)
{
if (m_maxDepth <= 1)
return false;
int newDepth = m_maxDepth - 1;
m_left = createChild( m_min, m_center, newDepth);
m_right = createChild(m_center, m_max, newDepth);
return true;
} // MxCifBinTree::split
/**
* Adds an object to the tree.
*
* @param object the object to add
*
* @return true if the object was added, false if not
*/
bool MxCifQuadTree::MxCifBinTree::addObject(const MxCifQuadTreeBounds & object)
{
// see if the object fits entirely within us
if (isObjectInRange(object))
{
// try putting the object in a child node
if (m_maxDepth > 1)
{
if (m_left == NULL)
{
if (!split())
return false;
}
if (m_left->addObject(object) ||
m_right->addObject(object))
{
return true;
}
}
// add the object to us
m_objects.push_back(&object);
return true;
}
else
return false;
} // MxCifBinTree::addObject
/**
* Removes an object from the tree.
*
* @param object the object to remove
*
* @return true if the object was removed, false if not
*/
bool MxCifQuadTree::MxCifBinTree::removeObject(const MxCifQuadTreeBounds & object)
{
// see if the object fits entirely within us
if (isObjectInRange(object))
{
if (m_maxDepth > 1)
{
if (m_left != NULL)
{
// check if the object is in a sub-node
if (m_left->removeObject(object) ||
m_right->removeObject(object))
{
return true;
}
}
}
// remove the object from us
std::vector<const MxCifQuadTreeBounds *>::iterator result = std::find(
m_objects.begin(), m_objects.end(), &object);
if (result != m_objects.end())
{
m_objects.erase(result);
return true;
}
}
return false;
} // MxCifBinTree::removeObject
/**
* Returns all the objects in the tree.
*
* @param objects vector that will be filled in with the objects that contain the point
*/
void MxCifQuadTree::MxCifBinTree::getAllObjects(
std::vector<const MxCifQuadTreeBounds *> & objects) const
{
// if we have sub-trees, pass the point to the tree that contains it
if (m_left != NULL)
{
m_right->getAllObjects(objects);
m_left->getAllObjects(objects);
}
for (std::vector<const MxCifQuadTreeBounds *>::const_iterator iter = m_objects.begin();
iter != m_objects.end(); ++iter)
{
objects.push_back(*iter);
}
} // MxCifBinTree::getAllObjects
//==============================================================================
/**
* Class destructor.
*/
MxCifQuadTree::MxCifXBinTree::~MxCifXBinTree()
{
} // MxCifXBinTree::~MxCifXBinTree
/**
* Checks if an object's x-axis range is contained within our range.
*
* @param object the object to check
*
* @return true if we caontain the object, false if not
*/
bool MxCifQuadTree::MxCifXBinTree::isObjectInRange(const MxCifQuadTreeBounds & object) const
{
// see if the object fits entirely within us
if (object.getMaxX() <= m_max &&
object.getMinX() >= m_min)
{
return true;
}
return false;
} // MxCifXBinTree::isObjectInRange
/**
* Finds all the objects that contain a given point.
*
* @param x x coordinate of the point
* @param y y coordinate of the point
* @param objects vector that will be filled in with the objects that contain the point
*/
void MxCifQuadTree::MxCifXBinTree::getObjectsAt(float x, float y,
std::vector<const MxCifQuadTreeBounds *> & objects) const
{
// find if we contain the point
if (x <= m_max &&
x >= m_min)
{
// if we have sub-trees, pass the point to the tree that contains it
if (m_left != NULL)
{
if (x >= m_center)
m_right->getObjectsAt(x, y, objects);
else
m_left->getObjectsAt(x, y, objects);
}
// check against each object in our list
for (std::vector<const MxCifQuadTreeBounds *>::const_iterator iter = m_objects.begin();
iter != m_objects.end(); ++iter)
{
const MxCifQuadTreeBounds * object = *iter;
if (object->isPointIn(x, y))
{
objects.push_back(object);
}
}
}
} // MxCifXBinTree::getObjectsAt
//==============================================================================
/**
* Class destructor.
*/
MxCifQuadTree::MxCifYBinTree::~MxCifYBinTree()
{
} // MxCifYBinTree::~MxCifYBinTree
/**
* Checks if an object's y-axis range is contained within our range.
*
* @param object the object to check
*
* @return true if we caontain the object, false if not
*/
bool MxCifQuadTree::MxCifYBinTree::isObjectInRange(const MxCifQuadTreeBounds & object) const
{
// see if the object fits entirely within us
if (object.getMaxY() <= m_max &&
object.getMinY() >= m_min)
{
return true;
}
return false;
} // MxCifYBinTree::isObjectInRange
/**
* Finds all the objects that contain a given point.
*
* @param x x coordinate of the point
* @param y y coordinate of the point
* @param objects vector that will be filled in with the objects that contain the point
*/
void MxCifQuadTree::MxCifYBinTree::getObjectsAt(float x, float y,
std::vector<const MxCifQuadTreeBounds *> & objects) const
{
// find if we contain the point
if (y <= m_max &&
y >= m_min)
{
// if we have sub-trees, pass the point to the tree that contains it
if (m_left != NULL)
{
if (y >= m_center)
m_right->getObjectsAt(x, y, objects);
else
m_left->getObjectsAt(x, y, objects);
}
// check against each object in our list
for (std::vector<const MxCifQuadTreeBounds *>::const_iterator iter = m_objects.begin();
iter != m_objects.end(); ++iter)
{
const MxCifQuadTreeBounds * object = *iter;
if (object->isPointIn(x, y))
{
objects.push_back(object);
}
}
}
} // MxCifYBinTree::getObjectsAt
//==============================================================================
@@ -0,0 +1,163 @@
// ======================================================================
//
// MxCifQuadTree.h
//
// Copyright 2002, Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_MxCifQuadTree_H
#define INCLUDED_MxCifQuadTree_H
#include <vector>
//==============================================================================
/*******************************************************************************
An mx-cif quadtree is a quadtree that stores an object at the minimum quad
that completely contains the object. They are further sub-divided into a
one-dimentional variation of the mx-cif quadtree (mx-cif bintree) based on
if the object crosses the x or y axis of the quad (objects that cross both are
placed in the y-axis bintree).
There is an optimization of the mx-cif quadtree that could be implemented (at
the expense of more memory) where the object is sub-divided and put into
a quad one lower than its normal level. This is very similar to what is done
in bsp trees.
See http://www.cs.umd.edu/users/brabec/quadtree/rectangles/cifquad.html, or
"Design and Analysis of Spatial Data Structures" by H. Samet (which
unfortunately is out of print).
*******************************************************************************/
//==============================================================================
class MxCifQuadTreeBounds;
//==============================================================================
class MxCifQuadTree
{
public:
MxCifQuadTree(float minX, float minY, float maxX, float maxY, int maxDepth);
~MxCifQuadTree();
bool addObject(const MxCifQuadTreeBounds & object);
bool removeObject(const MxCifQuadTreeBounds & object);
void getObjectsAt(float x, float y, std::vector<const MxCifQuadTreeBounds *> & objects) const;
void getAllObjects(std::vector<const MxCifQuadTreeBounds *> & objects) const;
private:
/**
* A one-dimentional variation of an MxCifQuadTree
*/
class MxCifBinTree
{
public:
MxCifBinTree(float min, float max, int maxDepth);
virtual ~MxCifBinTree();
bool addObject(const MxCifQuadTreeBounds & object);
bool removeObject(const MxCifQuadTreeBounds & object);
virtual void getObjectsAt(float x, float y, std::vector<const MxCifQuadTreeBounds *> & objects) const = 0;
void getAllObjects(std::vector<const MxCifQuadTreeBounds *> & objects) const;
protected:
bool split(void);
virtual MxCifBinTree * createChild(float min, float max, int maxDepth) const = 0;
virtual bool isObjectInRange(const MxCifQuadTreeBounds & object) const = 0;
protected:
float m_min; // min value of our range
float m_max; // max value of our range
float m_center; // center range value computed from the bounds
int m_maxDepth; // max depth we can recurse from our level
MxCifBinTree * m_left; // left child
MxCifBinTree * m_right; // right child
// @todo: use an auto_ptr here?
std::vector<const MxCifQuadTreeBounds *> m_objects; // objects that are contained in our bounds
};
/**
* An MxCifBinTree optimized for searches in the X direction.
*/
class MxCifXBinTree : public MxCifBinTree
{
public:
MxCifXBinTree(float min, float max, int maxDepth);
virtual ~MxCifXBinTree();
virtual void getObjectsAt(float x, float y, std::vector<const MxCifQuadTreeBounds *> & objects) const;
protected:
virtual MxCifBinTree * createChild(float min, float max, int maxDepth) const
{
return new MxCifXBinTree(min, max, maxDepth);
}
virtual bool isObjectInRange(const MxCifQuadTreeBounds & object) const;
};
/**
* An MxCifBinTree optimized for searches in the Y direction.
*/
class MxCifYBinTree : public MxCifBinTree
{
public:
MxCifYBinTree(float min, float max, int maxDepth);
virtual ~MxCifYBinTree();
virtual void getObjectsAt(float x, float y, std::vector<const MxCifQuadTreeBounds *> & objects) const;
protected:
virtual MxCifBinTree * createChild(float min, float max, int maxDepth) const
{
return new MxCifXBinTree(min, max, maxDepth);
}
virtual bool isObjectInRange(const MxCifQuadTreeBounds & object) const;
};
private:
bool split(void);
private:
float m_minX, m_minY; // lower-left bound
float m_maxX, m_maxY; // upper-right bound
float m_centerX, m_centerY; // center computed from the bounds
int m_maxDepth; // max depth we can recurse from our level
MxCifQuadTree * m_urTree; // upper-right child
MxCifQuadTree * m_ulTree; // upper-left child
MxCifQuadTree * m_llTree; // lower-left child
MxCifQuadTree * m_lrTree; // lower-right child
MxCifXBinTree m_xAxisTree; // objects that have a minimum intersection of the x-axis
MxCifYBinTree m_yAxisTree; // objects that have a minimum intersection of the -axis
};
//==============================================================================
inline MxCifQuadTree::MxCifXBinTree::MxCifXBinTree(float min, float max, int maxDepth) :
MxCifQuadTree::MxCifBinTree(min, max, maxDepth)
{
}
inline MxCifQuadTree::MxCifYBinTree::MxCifYBinTree(float min, float max, int maxDepth) :
MxCifQuadTree::MxCifBinTree(min, max, maxDepth)
{
}
#endif // INCLUDED_MxCifQuadTree_H
@@ -0,0 +1,41 @@
// ======================================================================
//
// MxCifQuadTreeBounds.cpp
//
// Copyright 2002, Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/MxCifQuadTreeBounds.h"
/**
* Returns if a given point is in our area.
*
* @param x x coordinate of the point
* @param y y coordinate of the point
*
* @return true we contain the point, false if not
*/
bool MxCifQuadTreeBounds::isPointIn(float x, float y) const
{
return (x >= m_minX && x <= m_maxX && y >= m_minY && y <= m_maxY);
} // MxCifQuadTreeBounds::isPointIn
//==============================================================================
/*
Returns if a given point is in our area.
*
* @param x x coordinate of the point
* @param y y coordinate of the point
*
* @return true we contain the point, false if not
*/
bool MxCifQuadTreeCircleBounds::isPointIn(float x, float y) const
{
float dx = x - m_centerX;
float dy = y - m_centerY;
return (dx * dx + dy * dy) <= m_radiusSquared;
} // MxCifQuadTreeCircleBounds::isPointIn
@@ -0,0 +1,141 @@
// ======================================================================
//
// MxCifQuadTreeBounds.h
//
// Copyright 2002, Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_MxCifQuadTreeBounds_H
#define INCLUDED_MxCifQuadTreeBounds_H
//==============================================================================
/**
* Base class used in MxCifQuadTree. Keeps track of the bounds of a 2-d geometric
* shape.
*/
class MxCifQuadTreeBounds
{
public:
MxCifQuadTreeBounds(float minX, float minY, float maxX, float maxY, void * data = NULL);
const float getMinX(void) const;
const float getMinY(void) const;
const float getMaxX(void) const;
const float getMaxY(void) const;
void * getData(void) const;
virtual bool isPointIn(float x, float y) const;
private:
MxCifQuadTreeBounds();
MxCifQuadTreeBounds(const MxCifQuadTreeBounds &);
MxCifQuadTreeBounds & operator =(const MxCifQuadTreeBounds &);
private:
const float m_minX, m_minY; // lower-left bound (--)
const float m_maxX, m_maxY; // upper-right bound (++)
void * m_data; // data associated with the area
};
//------------------------------------------------------------------------------
inline MxCifQuadTreeBounds::MxCifQuadTreeBounds(float minX, float minY, float maxX,
float maxY, void * data) :
m_minX(minX),
m_minY(minY),
m_maxX(maxX),
m_maxY(maxY),
m_data(data)
{
}
inline const float MxCifQuadTreeBounds::getMinX(void) const
{
return m_minX;
}
inline const float MxCifQuadTreeBounds::getMinY(void) const
{
return m_minY;
}
inline const float MxCifQuadTreeBounds::getMaxX(void) const
{
return m_maxX;
}
inline const float MxCifQuadTreeBounds::getMaxY(void) const
{
return m_maxY;
}
inline void * MxCifQuadTreeBounds::getData(void) const
{
return m_data;
}
//==============================================================================
/**
* A circular area for use in a MxCifQuadTree.
*/
class MxCifQuadTreeCircleBounds : public MxCifQuadTreeBounds
{
public:
MxCifQuadTreeCircleBounds(float centerX, float centerY, float radius, void * data = NULL);
float getCenterX() const;
float getCenterY() const;
float getRadius() const;
virtual bool isPointIn(float x, float y) const;
private:
MxCifQuadTreeCircleBounds();
MxCifQuadTreeCircleBounds(const MxCifQuadTreeCircleBounds &);
MxCifQuadTreeCircleBounds & operator =(const MxCifQuadTreeCircleBounds &);
private:
const float m_centerX, m_centerY;
const float m_radius;
const float m_radiusSquared;
};
//------------------------------------------------------------------------------
inline MxCifQuadTreeCircleBounds::MxCifQuadTreeCircleBounds(float centerX,
float centerY, float radius, void * data) :
MxCifQuadTreeBounds(centerX - radius, centerY - radius, centerX + radius,
centerY + radius, data),
m_centerX(centerX),
m_centerY(centerY),
m_radius(radius),
m_radiusSquared(radius * radius)
{
}
inline float MxCifQuadTreeCircleBounds::getCenterX() const
{
return m_centerX;
}
inline float MxCifQuadTreeCircleBounds::getCenterY() const
{
return m_centerY;
}
inline float MxCifQuadTreeCircleBounds::getRadius() const
{
return m_radius;
}
//==============================================================================
#endif // INCLUDED_MxCifQuadTreeBounds_H
@@ -0,0 +1,64 @@
// ======================================================================
//
// PackedArgb.cpp
// copyright 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/PackedArgb.h"
#include "sharedMath/VectorArgb.h"
// ======================================================================
const real PackedArgb::oo255 = RECIP (255);
const PackedArgb PackedArgb::solidBlack (255, 0, 0, 0);
const PackedArgb PackedArgb::solidBlue (255, 0, 0, 255);
const PackedArgb PackedArgb::solidCyan (255, 0, 255, 255);
const PackedArgb PackedArgb::solidGreen (255, 0, 255, 0);
const PackedArgb PackedArgb::solidRed (255, 255, 0, 0);
const PackedArgb PackedArgb::solidMagenta (255, 255, 0, 255);
const PackedArgb PackedArgb::solidYellow (255, 255, 255, 0);
const PackedArgb PackedArgb::solidWhite (255, 255, 255, 255);
const PackedArgb PackedArgb::solidGray (255, 128, 128, 128);
// ======================================================================
PackedArgb const PackedArgb::linearInterpolate(PackedArgb const & color1, PackedArgb const & color2, float const t)
{
return PackedArgb(
static_cast<uint8>(::linearInterpolate(static_cast<int>(color1.getA()), static_cast<int>(color2.getA()), t)),
static_cast<uint8>(::linearInterpolate(static_cast<int>(color1.getR()), static_cast<int>(color2.getR()), t)),
static_cast<uint8>(::linearInterpolate(static_cast<int>(color1.getG()), static_cast<int>(color2.getG()), t)),
static_cast<uint8>(::linearInterpolate(static_cast<int>(color1.getB()), static_cast<int>(color2.getB()), t)));
}
// ======================================================================
/**
* Construct a PackedArgb value.
* @param argb The initial component values.
*/
//#include "sharedMath/VectorArgb.h"
PackedArgb::PackedArgb(const VectorArgb &argb)
: m_argb(convert(argb.a, argb.r, argb.g, argb.b))
{
}
// ----------------------------------------------------------------------
/**
* Set the color.
* @argb The new alpha and color value.
*/
void PackedArgb::setArgb(const VectorArgb &argb)
{
m_argb = convert(argb.a, argb.r, argb.g, argb.b);
}
// ======================================================================
@@ -0,0 +1,278 @@
// ======================================================================
//
// PackedArgb.h
// copyright 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_PackedArgb_H
#define INCLUDED_PackedArgb_H
// ======================================================================
class VectorArgb;
// ======================================================================
class PackedArgb
{
private:
static const real oo255;
public:
static const PackedArgb solidBlack;
static const PackedArgb solidBlue;
static const PackedArgb solidCyan;
static const PackedArgb solidGray;
static const PackedArgb solidGreen;
static const PackedArgb solidRed;
static const PackedArgb solidMagenta;
static const PackedArgb solidYellow;
static const PackedArgb solidWhite;
public:
static PackedArgb const linearInterpolate(PackedArgb const & color1, PackedArgb const & color2, float t);
public:
PackedArgb();
PackedArgb(uint32 argb);
PackedArgb(uint8 a, uint8 r, uint8 g, uint8 b);
PackedArgb(const VectorArgb &color);
uint32 getArgb() const;
uint8 getA() const;
uint8 getR() const;
uint8 getG() const;
uint8 getB() const;
void setArgb(uint32 Argb);
void setArgb(uint8 a, uint8 r, uint8 g, uint8 b);
void setArgb(const VectorArgb &argb);
void setA(uint8 a);
void setR(uint8 r);
void setG(uint8 g);
void setB(uint8 b);
bool operator==(const PackedArgb &rhs) const;
bool operator!=(const PackedArgb &rhs) const;
private:
static uint32 convert(uint8 a, uint8 r, uint8 g, uint8 b);
static uint32 convert(float a, float r, float g, float b);
private:
// The representation of this cannot change without ramification. At least
// VertexBuffer assumes it can cast a uint32 argb to a PackedArgb without error.
uint32 m_argb;
};
// ======================================================================
inline uint32 PackedArgb::convert(uint8 a, uint8 r, uint8 g, uint8 b)
{
return
static_cast<uint32>(a) << 24 |
static_cast<uint32>(r) << 16 |
static_cast<uint32>(g) << 8 |
static_cast<uint32>(b) << 0;
}
// ----------------------------------------------------------------------
inline uint32 PackedArgb::convert(float a, float r, float g, float b)
{
return convert(static_cast<uint8>(a * 255.0f), static_cast<uint8>(r * 255.0f), static_cast<uint8>(g * 255.0f), static_cast<uint8>(b * 255.0f));
}
// ======================================================================
/**
* Construct a default PackedArgb value.
* All components will be set to 0.
*/
inline PackedArgb::PackedArgb()
: m_argb(0)
{
}
// ----------------------------------------------------------------------
/**
* Construct a PackedArgb value.
* @param argb The initial component values.
*/
inline PackedArgb::PackedArgb(uint32 argb)
: m_argb(argb)
{
}
// ----------------------------------------------------------------------
/**
* Construct a PackedArgb value.
* @param a The initial alpha component.
* @param r The initial red component.
* @param g The initial green component.
* @param a The initial blue component.
*/
inline PackedArgb::PackedArgb (uint8 a, uint8 r, uint8 g, uint8 b)
: m_argb(convert(a, r, g, b))
{
}
// ----------------------------------------------------------------------
/**
* Return (a,r,g,b) value as a uint32 value with alpha component at MSB and blue component at LSB.
* @return the packed argb value
*/
inline uint32 PackedArgb::getArgb() const
{
return m_argb;
}
// ----------------------------------------------------------------------
/**
* Return the alpha component.
* @return the alpha component.
*/
inline uint8 PackedArgb::getA() const
{
return static_cast<uint8>((m_argb >> 24) & 0xff);
}
// ----------------------------------------------------------------------
/**
* Return the red component.
* @return the red component.
*/
inline uint8 PackedArgb::getR() const
{
return static_cast<uint8>((m_argb >> 16) & 0xff);
}
// ----------------------------------------------------------------------
/**
* Return the green component.
* @return the green component.
*/
inline uint8 PackedArgb::getG() const
{
return static_cast<uint8>((m_argb >> 8) & 0xff);
}
// ----------------------------------------------------------------------
/**
* Return the blue component.
* @return the blue component.
*/
inline uint8 PackedArgb::getB() const
{
return static_cast<uint8>((m_argb >> 0) & 0xff);
}
// ----------------------------------------------------------------------
/**
* Set the color.
* @param a Alpha value.
* @param r Red value.
* @param g Green value.
* @param b Blue value.
*/
inline void PackedArgb::setArgb(uint8 a, uint8 r, uint8 g, uint8 b)
{
m_argb = convert(a, r, g, b);
}
// ----------------------------------------------------------------------
/**
* Set the alpha and color.
* @param a Alpha value.
* @param r Red value.
* @param g Green value.
* @param b Blue value.
*/
inline void PackedArgb::setArgb(uint32 argb)
{
m_argb = argb;
}
// ----------------------------------------------------------------------
/**
* Set the alpha component.
* @param a New alpha component value.
*/
inline void PackedArgb::setA(uint8 a)
{
m_argb = (static_cast<uint32>(a) << 24) | (m_argb & 0x00ffffff);
}
// ----------------------------------------------------------------------
/**
* Set the red component.
* @param r New red component value.
*/
inline void PackedArgb::setR(uint8 r)
{
m_argb = (static_cast<uint32>(r) << 16) | (m_argb & 0xff00ffff);
}
// ----------------------------------------------------------------------
/**
* Set the red component.
* @param g New green component value.
*/
inline void PackedArgb::setG(uint8 g)
{
m_argb = (static_cast<uint32>(g) << 8) | (m_argb & 0xffff00ff);
}
// ----------------------------------------------------------------------
/**
* Set the red component.
* @param b New blue component value.
*/
inline void PackedArgb::setB(uint8 b)
{
m_argb = (static_cast<uint32>(b) << 0) | (m_argb & 0xffffff00);
}
// ----------------------------------------------------------------------
/**
* Compare two PackedArgb colors.
* @return true if all the components are identical, otherwise false.
*/
inline bool PackedArgb::operator==(const PackedArgb &rhs) const
{
return m_argb == rhs.m_argb;
}
// ----------------------------------------------------------------------
/**
* Compare two PackedArgb colors.
* @return true if any component is different, otherwise false.
*/
inline bool PackedArgb::operator !=(const PackedArgb& rhs) const
{
return !(*this == rhs);
}
// ======================================================================
#endif
@@ -0,0 +1,75 @@
//===================================================================
//
// PackedRgb.cpp
// asommers 6-20-2000
//
// copyright 2000, verant interactive
//
//===================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/PackedRgb.h"
#include "sharedMath/VectorArgb.h"
//===================================================================
const float PackedRgb::oo255 = RECIP (255);
const PackedRgb PackedRgb::solidBlack ( 0, 0, 0);
const PackedRgb PackedRgb::solidBlue ( 0, 0, 255);
const PackedRgb PackedRgb::solidCyan ( 0, 255, 255);
const PackedRgb PackedRgb::solidGreen ( 0, 255, 0);
const PackedRgb PackedRgb::solidRed (255, 0, 0);
const PackedRgb PackedRgb::solidMagenta (255, 0, 255);
const PackedRgb PackedRgb::solidYellow (255, 255, 0);
const PackedRgb PackedRgb::solidWhite (255, 255, 255);
const PackedRgb PackedRgb::solidGray (128, 128, 128);
const PackedRgb PackedRgb::solidOrange (255, 128, 0);
//===================================================================
VectorArgb PackedRgb::convert (float alpha) const
{
return VectorArgb (
alpha,
static_cast<float> (r) * oo255,
static_cast<float> (g) * oo255,
static_cast<float> (b) * oo255);
}
//-------------------------------------------------------------------
void PackedRgb::convert (const VectorArgb& color)
{
r = static_cast<uint8> (color.r * 255.f);
g = static_cast<uint8> (color.g * 255.f);
b = static_cast<uint8> (color.b * 255.f);
}
//-------------------------------------------------------------------
bool PackedRgb::operator== (const PackedRgb& rhs) const
{
return r == rhs.r && g == rhs.g && b == rhs.b;
}
//-------------------------------------------------------------------
bool PackedRgb::operator!= (const PackedRgb& rhs) const
{
return r != rhs.r || g != rhs.g || b != rhs.b;
}
//-------------------------------------------------------------------
const PackedRgb PackedRgb::linearInterpolate (const PackedRgb& color1, const PackedRgb& color2, float t)
{
return PackedRgb (
static_cast<uint8> (::linearInterpolate (static_cast<int> (color1.r), static_cast<int> (color2.r), t)),
static_cast<uint8> (::linearInterpolate (static_cast<int> (color1.g), static_cast<int> (color2.g), t)),
static_cast<uint8> (::linearInterpolate (static_cast<int> (color1.b), static_cast<int> (color2.b), t)));
}
//===================================================================
@@ -0,0 +1,87 @@
//===================================================================
//
// PackedRgb.h
// asommers 6-20-2000
//
// copyright 2000, verant interactive
//
//===================================================================
#ifndef INCLUDED_PackedRgb_H
#define INCLUDED_PackedRgb_H
//===================================================================
class VectorArgb;
//===================================================================
class PackedRgb
{
private:
static const float oo255;
public:
static const PackedRgb solidBlack;
static const PackedRgb solidBlue;
static const PackedRgb solidCyan;
static const PackedRgb solidGray;
static const PackedRgb solidGreen;
static const PackedRgb solidRed;
static const PackedRgb solidMagenta;
static const PackedRgb solidYellow;
static const PackedRgb solidWhite;
static const PackedRgb solidOrange;
public:
uint8 r;
uint8 g;
uint8 b;
public:
PackedRgb ();
PackedRgb (uint8 newR, uint8 newG, uint8 newB);
VectorArgb convert (float alpha=1.f) const;
void convert (const VectorArgb& color);
uint32 asUint32() const;
bool operator== (const PackedRgb& rhs) const;
bool operator!= (const PackedRgb& rhs) const;
static const PackedRgb linearInterpolate (const PackedRgb& color1, const PackedRgb& color2, float t);
};
//===================================================================
inline PackedRgb::PackedRgb () :
r (0),
g (0),
b (0)
{
}
//-------------------------------------------------------------------
inline PackedRgb::PackedRgb (uint8 newR, uint8 newG, uint8 newB) :
r (newR),
g (newG),
b (newB)
{
}
//-------------------------------------------------------------------
inline uint32 PackedRgb::asUint32() const
{
return (static_cast<uint32>(r) << 16) | (static_cast<uint32>(g) << 8) | (static_cast<uint32>(b) << 0);
}
//===================================================================
#endif
@@ -0,0 +1,609 @@
// ======================================================================
//
// PaletteArgb.cpp
// Copyright 2002 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/PaletteArgb.h"
#include "fileInterface/AbstractFile.h"
#include "sharedFile/TreeFile.h"
#include "sharedFoundation/ExitChain.h"
#include "sharedMath/PackedArgb.h"
#include "sharedMath/PaletteArgbList.h"
#include "sharedFoundation/MemoryBlockManager.h"
#include <limits>
#include <vector>
#include <cstdio>
// ======================================================================
bool PaletteArgb::ms_installed;
MemoryBlockManager *PaletteArgb::ms_memoryBlockManager;
// ======================================================================
/**
* Install the PaletteArgb class.
*
* This function call must be made prior to creating or using any
* PaletteArgb instances. As of this writing, this function call is
* invoked via SetupSharedMath::install(). The caller should ensure
* SetupSharedMath::install() is invoked in any application that will
* use PaletteArgb.
*
* @see SetupSharedMath::install().
*/
void PaletteArgb::install()
{
DEBUG_FATAL(ms_installed, ("PaletteArgb already installed"));
ms_memoryBlockManager = new MemoryBlockManager("PaletteArgb", true, sizeof(PaletteArgb), 0, 0, 0);
ms_installed = true;
ExitChain::add(remove, "PaletteArgb");
}
// ----------------------------------------------------------------------
/**
* Allocate storage for a new dynamically allocated PaletteArgb
* instance.
*
* PaletteArgb memory is managed by a MemoryBlockManager.
*/
void *PaletteArgb::operator new(size_t size)
{
DEBUG_FATAL(!ms_installed, ("PaletteArgb not installed"));
DEBUG_FATAL(size != sizeof(PaletteArgb), ("PaletteArgb::operator new() doesn't support allocation for child classes"));
UNREF(size);
return ms_memoryBlockManager->allocate();
}
// ----------------------------------------------------------------------
/**
* Free storage associated with a dynamically allocated PaletteArgb
* instance.
*
* PaletteArgb memory is managed by a MemoryBlockManager.
*/
void PaletteArgb::operator delete(void *data)
{
DEBUG_FATAL(!ms_installed, ("PaletteArgb not installed"));
if (data)
ms_memoryBlockManager->free(data);
}
// ======================================================================
/**
* Contruct a modifiable PaletteArgb instance supporting a specified
* number of palette entries.
*
* The number of palette entries handled by the palette may never
* change from the value provided in the constructor.
*
* Since callers using this interface do no go through the
* PaletteArgbList::fetch() interface, the caller must perform
* a fetch() on the instance after construction completes. When
* the caller is done with the instance, call release() to destroy
* it.
*
* @param entryCount the number of palette entries in the palette.
*/
PaletteArgb::PaletteArgb(int entryCount) :
m_name(),
m_referenceCount(0),
m_entries(new PackedArgbVector())
{
DEBUG_FATAL(!ms_installed, ("PaletteArgb not installed"));
if (entryCount >= 0)
m_entries->resize(static_cast<size_t>(entryCount));
else
DEBUG_WARNING(true, ("PaletteArgb::PaletteArgb() bad entryCount [%d]", entryCount));
}
// ----------------------------------------------------------------------
PaletteArgb::PaletteArgb(PackedArgbVector const & packedArgbVector) :
m_name(),
m_referenceCount(0),
m_entries(new PackedArgbVector(packedArgbVector.begin(), packedArgbVector.end()))
{
DEBUG_FATAL(!ms_installed, ("PaletteArgb not installed"));
}
// ----------------------------------------------------------------------
/**
* Release a reference to the PaletteArgb instance.
*
* PaletteArgb::fetch() should be called for each logical reference
* the caller has for the instance. When the logical reference is
* no longer needed, it should be released with a call to PackedArgb::release().
* When no more references exist to a given PaletteArgb, typically
* it is destroyed.
*
* Failure to fetch() a reference
*/
void PaletteArgb::release() const
{
if (m_referenceCount < 1)
{
//-- Trying to track down a fatal for live. We will fatal in optimized builds, but we want to gracefully handle release builds
DEBUG_WARNING(true, ("PaletteArgb::release(%s): faulty reference count handling, ref count is [%d].", getName().getString(), m_referenceCount));
}
else
{
--m_referenceCount;
//-- We are going to let the PaletteArgbList keep references to the palettes and clean them up at the end.
#if 0
if (m_referenceCount == 0)
{
PaletteArgbList::stopTracking(*this);
delete const_cast<PaletteArgb*>(this);
}
#endif
}
}
// ----------------------------------------------------------------------
/**
* Return the number of palette entries stored in the palette.
*
* @return the number of palette entries stored in the palette.
*/
int PaletteArgb::getEntryCount() const
{
return static_cast<int>(m_entries->size());
}
// ----------------------------------------------------------------------
/**
* Retrieve a const reference to the specified palette entry.
*
* The specified palette entry must be in the range of 0 (inclusive)
* through getEntryCount()-1 (inclusive). Debug builds will FATAL
* if the precondition is not met, while undefined behavior ensues
* in release builds.
*
* @param index 0-based index of palette entry to retrieve.
*
* @return const reference to the specified palette entry.
*
* @see getEntryCount()
* @see PackedArgb
*/
const PackedArgb &PaletteArgb::getEntry(int index, bool & error) const
{
return const_cast<PaletteArgb *>(this)->getEntry(index, error);
}
// ----------------------------------------------------------------------
/**
* Retrieve a modifiable reference to the specified palette entry.
*
* The specified palette entry must be in the range of 0 (inclusive)
* through getEntryCount()-1 (inclusive). Debug builds will FATAL
* if the precondition is not met, while undefined behavior ensues
* in release builds.
*
* @param index 0-based index of palette entry to retrieve.
*
* @return modifiable reference to the specified palette entry.
*
* @see getEntryCount()
* @see PackedArgb
*/
PackedArgb &PaletteArgb::getEntry(int index, bool & error)
{
error = false;
const int size = static_cast<int>(m_entries->size ());
if (index < 0 || index >= size)
{
error = true;
DEBUG_WARNING(true, ("Designer/Art bug: [%s] Invalid index %d for range [%d-%d), clamping to 0: update object template customization data.", m_name.getString (), index, 0, size));
index = 0;
}
return (*m_entries)[static_cast<size_t>(index)];
}
// ----------------------------------------------------------------------
/**
* Write the palette to a Microsoft Palette (r) PAL file.
*
* The specified pathName is a platform filesystem name.
*
* @param pathName the platform-specific filesystem name where the
* palette data will be written.
*
* @return true if the palette data was written successfully to
* the file; false otherwise.
*/
bool PaletteArgb::write(const char *pathName) const
{
//-- write palette data to a temp buffer
const int MAX_ENTRY_COUNT = 1024;
const int BUFFER_SIZE = MAX_ENTRY_COUNT * 4 + 24;
unsigned char buffer[BUFFER_SIZE];
int numberOfBytesWritten = 0;
if (!writeToBuffer(buffer, BUFFER_SIZE, numberOfBytesWritten))
{
WARNING(true, ("failed to write palette to temporary buffer."));
return false;
}
//-- write buffer to file
// open file
FILE *const file = fopen(pathName, "wb");
if (!file)
{
WARNING(true, ("failed to open file [%s] for writing.", pathName));
return false;
}
// write contents to file
const size_t unitsWritten = fwrite(buffer, static_cast<size_t>(numberOfBytesWritten), 1, file);
if (unitsWritten != 1)
{
WARNING(true, ("failed to write palette data (%d bytes) to file [%s].", numberOfBytesWritten, pathName));
return false;
}
// close file
IGNORE_RETURN(fclose(file));
//-- success
return true;
}
// ----------------------------------------------------------------------
/**
* Retrieve the index of the palette entry with a color that most closely
* matches the specified color.
*
* The algorithmic complexity of this function is O(n),
* where n = # entries in the palette.
*
* This function defines "closest color" to be the color with the minimum
* sum of squares separation from the target color.
*
* @return the index of the palette entry with a color that most closely
* matches the specified color. If the palette contains no entries,
* returns -1.
*/
int PaletteArgb::findClosestMatch(const PackedArgb &targetColor) const
{
NOT_NULL(m_entries);
int minValue = std::numeric_limits<int>::max();
int minIndex = -1;
const int tr = static_cast<int>(targetColor.getR());
const int tg = static_cast<int>(targetColor.getG());
const int tb = static_cast<int>(targetColor.getB());
const int ta = static_cast<int>(targetColor.getA());
int index = 0;
const PackedArgbVector::const_iterator endIt = m_entries->end();
for (PackedArgbVector::const_iterator it = m_entries->begin(); it != endIt; ++it, ++index)
{
//-- prevent excessive casting in sum of squares calculation
const int cr = static_cast<int>(it->getR());
const int cg = static_cast<int>(it->getG());
const int cb = static_cast<int>(it->getB());
const int ca = static_cast<int>(it->getA());
//-- compute sum of squares difference in color from target
const int value =
((cr - tr) * (cr - tr)) +
((cg - tg) * (cg - tg)) +
((cb - tb) * (cb - tb)) +
((ca - ta) * (ca - ta));
//-- check if we found the closest color
if (value < minValue)
{
minValue = value;
minIndex = index;
}
}
return minIndex;
}
// ======================================================================
void PaletteArgb::remove()
{
DEBUG_FATAL(!ms_installed, ("PaletteArgb not installed"));
delete ms_memoryBlockManager;
ms_memoryBlockManager = 0;
ms_installed = false;
}
// ======================================================================
PaletteArgb::PaletteArgb(const CrcString &pathName) :
m_name(pathName.getString(), true),
m_referenceCount(0),
m_entries(new PackedArgbVector())
{
DEBUG_FATAL(!ms_installed, ("PaletteArgb not installed"));
//-- load file contents
// open file
AbstractFile *const file = TreeFile::open(pathName.getString(), AbstractFile::PriorityData, false);
NOT_NULL(file);
// process file
load(*file);
delete file;
}
// ----------------------------------------------------------------------
PaletteArgb::~PaletteArgb()
{
delete m_entries;
}
// ----------------------------------------------------------------------
void PaletteArgb::load(AbstractFile &file)
{
const int MAX_ENTRY_COUNT = 1024;
const int BUFFER_SIZE = MAX_ENTRY_COUNT * 4 + 24;
unsigned char buffer[BUFFER_SIZE];
//-- load contents
// ensure file isn't too big
const int fileSize = file.length();
if (fileSize > BUFFER_SIZE)
{
WARNING(true, ("palette file [%s] too large, can't open, skipping data.", m_name.getString()));
return;
}
// ensure file isn't too small
if (fileSize < 24)
{
WARNING(true, ("palette file [%s] is too small to be a palette file, skipping data.", m_name.getString()));
return;
}
const int bytesRead = file.read(buffer, fileSize);
if (bytesRead != fileSize)
{
WARNING(true, ("palette file [%s] reported %d bytes, but only read %d bytes, skipping data.", m_name.getString(), fileSize, bytesRead));
return;
}
//-- verify header
int bufferPosition = 0;
// read RIFF FourCC
if (
(buffer[bufferPosition++] != 'R') ||
(buffer[bufferPosition++] != 'I') ||
(buffer[bufferPosition++] != 'F') ||
(buffer[bufferPosition++] != 'F'))
{
WARNING(true, ("palette file [%s] is missing RIFF header, skipping data.", m_name.getString()));
return;
}
// read RIFF chunk length (stored little-endian)
const uint riffLength =
(static_cast<uint>(buffer[bufferPosition + 0]) << 0) |
(static_cast<uint>(buffer[bufferPosition + 1]) << 8) |
(static_cast<uint>(buffer[bufferPosition + 2]) << 16) |
(static_cast<uint>(buffer[bufferPosition + 3]) << 24);
bufferPosition += 4;
// read 'PAL ' riff chunk designation
if (
(buffer[bufferPosition++] != 'P') ||
(buffer[bufferPosition++] != 'A') ||
(buffer[bufferPosition++] != 'L') ||
(buffer[bufferPosition++] != ' '))
{
WARNING(true, ("palette file [%s] is missing PAL riff data designation, skipping data.", m_name.getString()));
return;
}
//-- read palette data chunk
// read 'data' chunk FourCC
if (
(buffer[bufferPosition++] != 'd') ||
(buffer[bufferPosition++] != 'a') ||
(buffer[bufferPosition++] != 't') ||
(buffer[bufferPosition++] != 'a'))
{
WARNING(true, ("palette file [%s] is missing data chunk, skipping data.", m_name.getString()));
return;
}
// read palette chunk length
const uint paletteChunkLength =
(static_cast<uint>(buffer[bufferPosition + 0]) << 0) |
(static_cast<uint>(buffer[bufferPosition + 1]) << 8) |
(static_cast<uint>(buffer[bufferPosition + 2]) << 16) |
(static_cast<uint>(buffer[bufferPosition + 3]) << 24);
bufferPosition += 4;
const uint expectedRiffLength = paletteChunkLength + 12;
if (riffLength != expectedRiffLength)
{
WARNING(true, ("palette file [%s] riff chunk expected to be %u bytes, file says it is %u bytes, skipping data.", m_name.getString(), expectedRiffLength, riffLength));
return;
}
// read unknown byte (should be zero?)
const uint unknownPaletteValue01 = static_cast<uint>(buffer[bufferPosition++]);
if (unknownPaletteValue01 != 0)
{
WARNING(true, ("palette file [%s] has unknown palette value, usually 0, as [%u], just a warning.", m_name.getString(), unknownPaletteValue01));
}
// read palette component count or version # (3 is all test cases)
const uint versionOrComponentCount = static_cast<uint>(buffer[bufferPosition++]);
if (versionOrComponentCount != 3)
{
WARNING(true, ("palette file [%s] has component/version != 3 [%u], skipping data.", m_name.getString(), versionOrComponentCount));
return;
}
// read palette entry count
const uint entryCount =
(static_cast<uint>(buffer[bufferPosition + 0]) << 0) |
(static_cast<uint>(buffer[bufferPosition + 1]) << 8);
bufferPosition += 2;
if (static_cast<int>(entryCount) > MAX_ENTRY_COUNT)
{
WARNING(true, ("palette file [%s] has has %u entries, we support a max of %d, skipping data.", m_name.getString(), entryCount, MAX_ENTRY_COUNT));
return;
}
//-- do sanity checking on palette count vs. chunk size
const uint expectedPaletteChunkLength = 4 + entryCount * 4;
if (paletteChunkLength != expectedPaletteChunkLength)
{
WARNING(true, ("palette file [%s] palette chunk expected to be %u bytes, file says it is %u bytes, skipping data.", m_name.getString(), expectedPaletteChunkLength, paletteChunkLength));
return;
}
//-- load the data
m_entries->resize(static_cast<size_t>(entryCount));
for (uint i = 0; i < entryCount; ++i)
{
PackedArgb &entry = (*m_entries)[static_cast<size_t>(i)];
entry.setR(buffer[bufferPosition++]);
entry.setG(buffer[bufferPosition++]);
entry.setB(buffer[bufferPosition++]);
entry.setA(buffer[bufferPosition++]);
//-- assume this variable indicates the number of components
if (versionOrComponentCount != 4)
{
// no alpha component, set to full-on
entry.setA(255);
}
}
}
// ----------------------------------------------------------------------
bool PaletteArgb::writeToBuffer(unsigned char *buffer, int bufferSize, int &numberOfBytesWritten) const
{
const int entryCount = getEntryCount();
const int requiredBufferSize = 24 + 4 * entryCount;
if (bufferSize < requiredBufferSize)
{
WARNING(true, ("writeToBuffer(): requires buffer size of %d, caller bufferSize is %d.", requiredBufferSize, bufferSize));
return false;
}
//-- write riff
unsigned char *const initialBuffer = buffer;
// write RIFF
*(buffer++) = 'R';
*(buffer++) = 'I';
*(buffer++) = 'F';
*(buffer++) = 'F';
// write riff chunk length
const uint riffChunkLength = 16 + 4 * static_cast<uint>(entryCount);
*(buffer++) = static_cast<unsigned char>((riffChunkLength >> 0) & 0xff);
*(buffer++) = static_cast<unsigned char>((riffChunkLength >> 8) & 0xff);
*(buffer++) = static_cast<unsigned char>((riffChunkLength >> 16) & 0xff);
*(buffer++) = static_cast<unsigned char>((riffChunkLength >> 24) & 0xff);
// write PAL data designation
*(buffer++) = 'P';
*(buffer++) = 'A';
*(buffer++) = 'L';
*(buffer++) = ' ';
// write palette chunk FourCC
*(buffer++) = 'd';
*(buffer++) = 'a';
*(buffer++) = 't';
*(buffer++) = 'a';
// write palette chunk length
const uint paletteChunkLength = 4 + 4 * static_cast<uint>(entryCount);
*(buffer++) = static_cast<unsigned char>((paletteChunkLength >> 0) & 0xff);
*(buffer++) = static_cast<unsigned char>((paletteChunkLength >> 8) & 0xff);
*(buffer++) = static_cast<unsigned char>((paletteChunkLength >> 16) & 0xff);
*(buffer++) = static_cast<unsigned char>((paletteChunkLength >> 24) & 0xff);
// write unknown byte. I've only seen 0 coming out of Photoshop 6.0.
*(buffer++) = 0;
// write component count/version (not sure what this is, but is 3 coming out of Photoshop 6.0)
const uint componentCount = 3;
*(buffer++) = static_cast<unsigned char>(componentCount);
// write entry count
const uint uiEntryCount = static_cast<uint>(entryCount);
*(buffer++) = static_cast<unsigned char>((uiEntryCount >> 0) & 0xff);
*(buffer++) = static_cast<unsigned char>((uiEntryCount >> 8) & 0xff);
// write data
for (uint i = 0; i < uiEntryCount; ++i)
{
const PackedArgb &entry = (*m_entries)[static_cast<size_t>(i)];
*(buffer++) = entry.getR();
*(buffer++) = entry.getG();
*(buffer++) = entry.getB();
*(buffer++) = entry.getA();
}
//-- sanity check: make sure the calculated # bytes is the number of bytes written.
// if not, either I wrote the wrong data or calculated the size wrong.
numberOfBytesWritten = (buffer - initialBuffer);
DEBUG_FATAL(numberOfBytesWritten != requiredBufferSize, ("palette data write failure, should have written %d bytes, wrote %d bytes.", requiredBufferSize, numberOfBytesWritten));
// success
return true;
}
// ======================================================================
@@ -0,0 +1,163 @@
// ======================================================================
//
// PaletteArgb.h
// Copyright 2002 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_PaletteArgb_H
#define INCLUDED_PaletteArgb_H
// ======================================================================
class AbstractFile;
class PackedArgb;
class PaletteArgbList;
class MemoryBlockManager;
#include "sharedFoundation/PersistentCrcString.h"
// ======================================================================
/**
* Provides for loading, manipulation and saving of color palette
* data.
*
* Color palette data may be read from and written to the
* Microsoft Palette (r) format, typically stored with the .PAL
* file extension. Adobe Photoshop can load and save .PAL files.
*
* The palette may have as few as zero entries or as many as
* 1024 entries. The upper limit on palette entry count is
* fixed by the file format at 65535 entries (2^32-1); however,
* for implementation efficiency this class only supports a
* maximum of 1024 entries. The size of palette data in the .PAL file
* is linearly related to the number of palette entries,
* 24 bytes + 4 * (# palette entries).
*
* PaletteArgb loading is accomplished via the PaletteArgbList
* class. The caller may not modify a loaded PaletteArgb instance.
*
* PaletteArgb instances may be created and modified via the public
* constructor. Currently the caller must specify the exact number
* of palette entries at time of construction. PaletteArgb supports
* writing to a file via the PaletteArgb::write() function.
*/
class PaletteArgb
{
friend class PaletteArgbList;
public:
static void install();
static void *operator new(size_t size);
static void operator delete(void *data);
public:
explicit PaletteArgb(int entryCount);
explicit PaletteArgb(stdvector<PackedArgb>::fwd const & packedArgbVector);
const CrcString &getName() const;
void fetch() const;
void release() const;
int getReferenceCount() const;
int getEntryCount() const;
const PackedArgb &getEntry(int index, bool & error) const;
PackedArgb &getEntry(int index, bool & error);
bool write(const char *pathName) const;
int findClosestMatch(const PackedArgb &targetColor) const;
private:
typedef stdvector<PackedArgb>::fwd PackedArgbVector;
private:
static void remove();
private:
PaletteArgb(const CrcString &pathName);
~PaletteArgb();
void load(AbstractFile &file);
bool writeToBuffer(unsigned char *buffer, int bufferSize, int &numberOfBytesWritten) const;
// disabled
PaletteArgb();
PaletteArgb(const PaletteArgb&);
PaletteArgb &operator =(const PaletteArgb&);
private:
static bool ms_installed;
static MemoryBlockManager *ms_memoryBlockManager;
private:
PersistentCrcString m_name;
mutable int m_referenceCount;
PackedArgbVector *const m_entries;
};
// ======================================================================
/**
* Return the pathname of the PaletteArgb instance.
*
* The pathname for the instance will be a non-zero-length string only
* if the PaletteArgb instance was loaded via PaletteArgbList.
*
* @return the pathname of the PaletteArgb if loaded; otherwise,
* zero-length string.
*
* @see PaletteArgbList
*/
inline const CrcString &PaletteArgb::getName() const
{
return m_name;
}
// ----------------------------------------------------------------------
/**
* Release a reference to the PaletteArgb instance.
*
* PaletteArgb::fetch() should be called for each logical reference
* the caller has for the instance. When the logical reference is
* no longer needed, it should be released with a call to PackedArgb::release().
* When no more references exist to a given PaletteArgb, typically
* it is destroyed.
*
* Failure to fetch() a reference
*/
inline void PaletteArgb::fetch() const
{
++m_referenceCount;
}
// ----------------------------------------------------------------------
/**
* Return the number of logical references existing on this
* PaletteArgb instance.
*
* @return the number of logical references existing on this
* PaletteArgb instance.
*/
inline int PaletteArgb::getReferenceCount() const
{
return m_referenceCount;
}
// ======================================================================
#endif
@@ -0,0 +1,242 @@
// ======================================================================
//
// PaletteArgbList.cpp
// Copyright 2002 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/PaletteArgbList.h"
#include "sharedFile/AsynchronousLoader.h"
#include "sharedFile/TreeFile.h"
#include "sharedFoundation/ExitChain.h"
#include "sharedFoundation/LessPointerComparator.h"
#include "sharedFoundation/TemporaryCrcString.h"
#include "sharedMath/PackedArgb.h"
#include "sharedMath/PaletteArgb.h"
#include "sharedSynchronization/Mutex.h"
#include <map>
// ======================================================================
namespace PaletteArgbListNamespace
{
Mutex s_criticalSection;
}
using namespace PaletteArgbListNamespace;
// ======================================================================
bool PaletteArgbList::ms_installed;
PaletteArgbList::ResourceMap *PaletteArgbList::ms_resourceMap;
// ======================================================================
/**
* Install the PaletteArgbList.
*
* This function must be invoked prior to using any
* other aspect of the PaletteArgbList class. As of this writing,
* PaletteArgbList::install() is invoked via SetupSharedMath::install().
*
* @see SetupSharedMath.
*/
void PaletteArgbList::install()
{
DEBUG_FATAL(ms_installed, ("PaletteArgbList already installed"));
ms_resourceMap = new ResourceMap();
ms_installed = true;
ExitChain::add(remove, "PaletteArgbList");
}
// ----------------------------------------------------------------------
/**
* Retrieve a PaletteArgb instance loaded from the specified filename.
*
* The specified pathName is the path to the Microsoft Palette (r) (.PAL)
* file to load via the TreeFile System. If the given file currently
* is loaded, the same instance with a bumped up reference count will
* be returned.
*
* This function bumps up the reference count on the returned instance.
* When the caller is done with the PaletteArgb, it should call
* PaletteArgb::release().
*
* If the specfied filename can not be found, a default palette with
* one all-zero entry will be returned along with a WARNING.
*
* @param pathName TreeFile-accessible pathname to a Microsoft Palette (r)
* file.
*
* @return the contents of the Palette file if the palette file
* exists; otherwise, a default palette instance.
*
* @see PaletteArgb::release().
*/
const PaletteArgb *PaletteArgbList::fetch(const CrcString &pathName)
{
return fetch(pathName, true);
}
// ----------------------------------------------------------------------
void PaletteArgbList::assignAsynchronousLoaderFunctions()
{
if (AsynchronousLoader::isInstalled())
AsynchronousLoader::bindFetchReleaseFunctions("pal", &asynchronousLoaderFetchNoCreate, &asynchronousLoaderRelease);
}
// ======================================================================
void PaletteArgbList::remove()
{
DEBUG_FATAL(!ms_installed, ("PaletteArgbList not installed"));
//-- release exisitng palettes, report memory leaks
//DEBUG_REPORT_LOG(!ms_resourceMap->empty(), ("PaletteArgbList: loaded [%u] palettes:", ms_resourceMap->size()));
const ResourceMap::iterator endIt = ms_resourceMap->end();
for (ResourceMap::iterator it = ms_resourceMap->begin(); it != endIt; ++it)
{
PaletteArgb const * palette = it->second;
// print leak info
NOT_NULL(palette);
DEBUG_WARNING(palette->getReferenceCount() > 0, (" palette [%s]: %d references outstanding", it->first->getString(), palette->getReferenceCount()));
// delete the resource
delete palette;
}
//-- delete the map
delete ms_resourceMap;
ms_resourceMap = 0;
ms_installed = false;
}
// ----------------------------------------------------------------------
void PaletteArgbList::stopTracking(const PaletteArgb &palette)
{
DEBUG_FATAL(!ms_installed, ("PaletteArgbList not installed"));
s_criticalSection.enter();
//-- check if this palette is named. if not, ignore it.
const char *const paletteName = palette.getName().getString();
if (!paletteName || !*paletteName)
{
// palette has no name, so the list isn't tracking it.
s_criticalSection.leave();
return;
}
//-- find it in our list.
const ResourceMap::iterator findIt = ms_resourceMap->find(&palette.getName());
if (findIt == ms_resourceMap->end())
{
// not found
DEBUG_WARNING(true, ("named palette [%s] not tracked, shouldn't happen.", palette.getName().getString()));
}
else
{
// found it
ms_resourceMap->erase(findIt);
}
s_criticalSection.leave();
}
// ----------------------------------------------------------------------
const void *PaletteArgbList::asynchronousLoaderFetchNoCreate(char const *fileName)
{
TemporaryCrcString cfn(fileName, true);
return PaletteArgbList::fetch(cfn, false);
}
// ----------------------------------------------------------------------
void PaletteArgbList::asynchronousLoaderRelease(void const *palette)
{
static_cast<PaletteArgb const *>(palette)->release();
}
// ----------------------------------------------------------------------
const PaletteArgb *PaletteArgbList::fetch(const CrcString &pathName, bool create)
{
DEBUG_FATAL(!ms_installed, ("PaletteArgbList not installed"));
s_criticalSection.enter();
//-- check if the pathName is cached
const ResourceMap::iterator lowerBoundResult = ms_resourceMap->lower_bound(&pathName);
const bool haveResource = ((lowerBoundResult != ms_resourceMap->end()) && !ms_resourceMap->key_comp()(&pathName, lowerBoundResult->first));
if (haveResource)
{
NOT_NULL(lowerBoundResult->second);
lowerBoundResult->second->fetch();
PaletteArgb const *const palette = lowerBoundResult->second;
s_criticalSection.leave();
return palette;
}
// resource doesn't exist
//-- Skip if not creating.
if (!create)
{
s_criticalSection.leave();
return 0;
}
PaletteArgb *palette = 0;
//-- check if referenced filename exists
if (!TreeFile::exists(pathName.getString()))
{
//-- palette file can't be found, return a new default palette.
// note: this palette doesn't get mapped, so every call for this
// non-existent palette will generate a new one. That's okay,
// this should be a rare occurrence. If it is not rare and acceptable,
// we'll want a single default palette allocated and returned.
WARNING(true, ("palette [%s] not found, using default palette.", pathName.getString()));
palette = new PaletteArgb(1);
// Set only color to something we can tell is a bug.
bool error = false;
PackedArgb &entry = palette->getEntry(0, error);
WARNING(error, ("PaletteArgbList::fetch error"));
entry.setArgb(255, 0, 255, 255);
}
else
{
//-- palette file found, load it
palette = new PaletteArgb(pathName);
//-- map resource to name
IGNORE_RETURN(ms_resourceMap->insert(lowerBoundResult, ResourceMap::value_type(&palette->getName(), palette)));
}
//-- bump up the reference count
NOT_NULL(palette);
palette->fetch();
s_criticalSection.leave();
return palette;
}
// ======================================================================
@@ -0,0 +1,63 @@
// ======================================================================
//
// PaletteArgbList.h
// Copyright 2002 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_PaletteArgbList_H
#define INCLUDED_PaletteArgbList_H
// ======================================================================
class CrcString;
class LessPointerComparator;
class PaletteArgb;
// ======================================================================
/**
* Manages PaletteArgb assets loaded via the TreeFile system.
*
* The PaletteArgbList coordinates handing out reference-counted
* PaletteArgb instances loaded from the TreeFile system. It ensures
* only a single instance of a Palette file is loaded at any given time.
*/
class PaletteArgbList
{
friend class PaletteArgb;
public:
static void install();
static const PaletteArgb *fetch(const CrcString &pathName);
static void assignAsynchronousLoaderFunctions();
private:
typedef stdmap<const CrcString *, PaletteArgb*, LessPointerComparator>::fwd ResourceMap;
private:
static void remove();
static void stopTracking(const PaletteArgb &palette);
static const void *asynchronousLoaderFetchNoCreate(char const *fileName);
static void asynchronousLoaderRelease(void const *palette);
static const PaletteArgb *fetch(const CrcString &pathName, bool create);
private:
static bool ms_installed;
static ResourceMap *ms_resourceMap;
};
// ======================================================================
#endif
@@ -0,0 +1,371 @@
// ======================================================================
//
// Plane.cpp
// jeff grills
//
// copyright 1998 Bootprint Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Plane.h"
#include "sharedMath/Transform.h"
// ======================================================================
// Construct a plane given three non-colinear points
//
// Remarks:
//
// The front half of the plane is the side from which the vertices would
// be specified in a clockwise order.
Plane::Plane(
const Vector &point0, // [IN] First point on the plane
const Vector &point1, // [IN] Second point on the plane
const Vector &point2 // [IN] Third point on the plane
)
: normal(),
d(CONST_REAL(0))
{
set(point0, point1, point2);
}
// ----------------------------------------------------------------------
/**
* Define a plane given three non-colinear points.
*
* The front half of the plane is the side from which the vertices would
* be specified in a clockwise order.
*
* @param point0 [IN] First point on the plane
* @param point1 [IN] Second point on the plane
* @param point2 [IN] Third point on the plane
*/
void Plane::set(const Vector &point0, const Vector &point1, const Vector &point2)
{
// calculate the new normal direction
normal = (point0 - point2).cross(point1 - point0);
// normalize the normal
if (!normal.normalize())
{
normal = Vector::unitZ;
DEBUG_WARNING(true, ("Plane::calculate could not normalize vector"));
}
// compute the plane D coefficient
d = -normal.dot(point0);
}
// ----------------------------------------------------------------------
/**
* Find the intersection between a line segment and the plane.
*
* If the line segment does intersect the plane, and the intersection
* pointer is non-NULL, then intersection will be set to the point on
* the line segment that crosses the plane.
*
* @param point0 [IN] Start of the line segment
* @param point1 [IN] End of the line segment
* @return True if the line segment intersects the plane, otherwise false.
*/
bool Plane::findIntersection(const Vector &point0, const Vector &point1) const
{
const real t0(computeDistanceTo(point0));
const real t1(computeDistanceTo(point1));
// check to make sure the endpoints span the plane
return (t0 * t1) < 0; // if either is zero, the point is on the plane
}
// ----------------------------------------------------------------------
/**
* Find the intersection between a line segment and the plane.
*
* If the line segment does intersect the plane, and the intersection
* pointer is non-NULL, then intersection will be set to the point on
* the line segment that crosses the plane.
*
* @param point0 [IN] Start of the line segment
* @param point1 [IN] End of the line segment
* @param intersection [OUT] Intersection of the point and the plane
* @return True if the line segment intersects the plane, otherwise false.
*/
bool Plane::findIntersection(const Vector &point0, const Vector &point1, Vector &intersection) const
{
const real t0(computeDistanceTo(point0));
const real t1(computeDistanceTo(point1));
// check to make sure the endpoints span the plane
if ((t0 * t1) > CONST_REAL(0))
return false;
if (t0 == t1) // both zero
{
intersection = point1;
return true;
}
float abst = t0 / (t0 - t1); // safe since sign of t0 is always opposite t1
intersection = Vector::linearInterpolate(point0, point1, abst);
return true;
}
// ----------------------------------------------------------------------
/**
* Find the intersection between a line segment and the plane.
*
* If the line segment does intersect the plane, and the intersection
* pointer is non-NULL, then intersection will be set to the point on
* the line segment that crosses the plane.
*
* @param point0 [IN] Start of the line segment
* @param point1 [IN] End of the line segment
* @param intersection [OUT] Intersection of the point and the plane
* @param t [OUT] parameterized t from 0..1
* @return True if the line segment intersects the plane, otherwise false.
*/
bool Plane::findIntersection(const Vector &point0, const Vector &point1, Vector &intersection, float &t) const
{
const real t0(computeDistanceTo(point0));
const real t1(computeDistanceTo(point1));
// check to make sure the endpoints span the plane
if ((t0 * t1) > CONST_REAL(0))
return false;
if (t0 == t1) // both zero
{
intersection = point0;
t=0;
return true;
}
float abst = t0 / (t0 - t1); // safe since sign of t0 is always opposite t1
intersection = Vector::linearInterpolate(point0, point1, abst);
t = abst;
return true;
}
// ----------------------------------------------------------------------
/**
* Find the intersection between a line segment and the plane.
*
* If the line segment does intersect the plane, and the intersection
* pointer is non-NULL, then intersection will be set to the point on
* the line segment that crosses the plane.
*
* @param point0 [IN] Start of the line segment
* @param point1 [IN] End of the line segment
* @param intersection [OUT] Intersection of the point and the plane
* @param t [OUT] parameterized t from 0..1
* @return True if the line segment intersects the plane, otherwise false.
*/
bool Plane::findIntersection(const Vector &point0, const Vector &point1, float &t) const
{
const real t0(computeDistanceTo(point0));
const real t1(computeDistanceTo(point1));
// check to make sure the endpoints span the plane
if ((t0 * t1) > CONST_REAL(0))
return false;
if (t0 == t1) // both zero
{
t=0;
return true;
}
t = t0 / (t0 - t1); // safe since sign of t0 is always opposite t1
return true;
}
// ----------------------------------------------------------------------
/**
* Find the directed intersection between a line segment and the plane.
*
* This routine will only detect the intersection if point0
* is on the front side of the plane, and point1 is on the
* back side of the plane.
*
* If the line segment does intersect the plane, and the intersection
* pointer is non-NULL, then intersection will be set to the point on
* the line segment that crosses the plane.
*
* @param point0 [IN] Start of the line segment
* @param point1 [IN] End of the line segment
* @return True if the line segment intersects the plane from front-to-rear, otherwise false.
*/
bool Plane::findDirectedIntersection(const Vector &point0, const Vector &point1) const
{
const real t0(computeDistanceTo(point0));
const real t1(computeDistanceTo(point1));
// check to make t0 is on the front side of the plane and t1 is on the back side of the plane
return !((t0 < CONST_REAL(0) || t1 > CONST_REAL(0)));
}
// ----------------------------------------------------------------------
/**
* Find the directed intersection between a line segment and the plane.
*
* This routine will only detect the intersection if point0
* is on the front side of the plane, and point1 is on the
* back side of the plane.
*
* If the line segment does intersect the plane, and the intersection
* pointer is non-NULL, then intersection will be set to the point on
* the line segment that crosses the plane.
*
* @param point0 [IN] Start of the line segment
* @param point1 [IN] End of the line segment
* @param intersection [OUT] Intersection of the point and the plane (may be NULL)
* @param t [OUT] parameterized t from 0..1
* @return True if the line segment intersects the plane from front-to-rear, otherwise false.
*/
bool Plane::findDirectedIntersection(const Vector &point0, const Vector &point1, Vector &intersection) const
{
const real t0(computeDistanceTo(point0));
const real t1(computeDistanceTo(point1));
// check to make t0 is on the front side of the plane and t1 is on the back side of the plane
if (t0 < CONST_REAL(0) || t1 > CONST_REAL(0))
return false;
if (t0 == t1) // both zero
{
intersection = point1;
return true;
}
// solve parametric equation to find the intersection point
float abst = t0 / (t0 - t1); // safe sine sign of t0 is always opposite t1
intersection = Vector::linearInterpolate(point0, point1, abst);
return true;
}
// ----------------------------------------------------------------------
/**
* Find the directed intersection between a line segment and the plane.
*
* This routine will only detect the intersection if point0
* is on the front side of the plane, and point1 is on the
* back side of the plane.
*
* If the line segment does intersect the plane, and the intersection
* pointer is non-NULL, then intersection will be set to the point on
* the line segment that crosses the plane.
*
* @param point0 [IN] Start of the line segment
* @param point1 [IN] End of the line segment
* @param intersection [OUT] Intersection of the point and the plane (may be NULL)
* @param t [OUT] parameterized t from 0..1
* @return True if the line segment intersects the plane from front-to-rear, otherwise false.
*/
bool Plane::findDirectedIntersection(const Vector &point0, const Vector &point1, Vector &intersection, real &t) const
{
const real t0(computeDistanceTo(point0));
const real t1(computeDistanceTo(point1));
// check to make t0 is on the front side of the plane and t1 is on the back side of the plane
if (t0 < CONST_REAL(0) || t1 > CONST_REAL(0))
return false;
if (t0 == t1) // both zero
{
intersection = point0;
t=0;
return true;
}
// solve parametric equation to find the intersection point
float abst = t0 / (t0 - t1); // safe sine sign of t0 is always opposite t1
t = abst;
intersection = Vector::linearInterpolate(point0, point1, abst);
return true;
}
// ----------------------------------------------------------------------
/**
* Find the directed intersection between a line segment and the plane.
*
* This routine will only detect the intersection if point0
* is on the front side of the plane, and point1 is on the
* back side of the plane.
*
* If the line segment does intersect the plane, and the intersection
* pointer is non-NULL, then intersection will be set to the point on
* the line segment that crosses the plane.
*
* @param point0 [IN] Start of the line segment
* @param point1 [IN] End of the line segment
* @param intersection [OUT] Intersection of the point and the plane (may be NULL)
* @param t [OUT] parameterized t from 0..1
* @return True if the line segment intersects the plane from front-to-rear, otherwise false.
*/
bool Plane::findDirectedIntersection(const Vector &point0, const Vector &point1, real &t) const
{
const real t0(computeDistanceTo(point0));
const real t1(computeDistanceTo(point1));
// check to make t0 is on the front side of the plane and t1 is on the back side of the plane
if (t0 < CONST_REAL(0) || t1 > CONST_REAL(0))
return false;
if (t0 == t1) // both zero
{
t=0;
return true;
}
// solve parametric equation to find the intersection point
float abst = t0 / (t0 - t1); // safe sine sign of t0 is always opposite t1
t = abst;
return true;
}
// ----------------------------------------------------------------------
/**
* Transform the plane by the specified transformation
*
* @param trans the transformation to apply.
*/
void Plane::transform (const Transform & trans)
{
Vector const & p = trans.rotateTranslate_l2p (normal * -d);
normal = trans.rotate_l2p (normal);
d = computeD (normal, p);
}
// ----------------------------------------------------------------------
/**
* Transform the plane by the specified transformation
*
* @param trans the transformation to apply.
*/
void Plane::transform_p2l(const Transform &trans)
{
Vector const & p = trans.rotateTranslate_p2l(normal * -d);
normal = trans.rotate_p2l(normal);
d = computeD (normal, p);
}
// ======================================================================
@@ -0,0 +1,245 @@
// ======================================================================
//
// Plane.h
// jeff grills
//
// copyright 1998 Bootprint Entertainment
//
// ======================================================================
#ifndef PLANE_H
#define PLANE_H
// ======================================================================
#include "sharedMath/Vector.h"
class Transform;
// ======================================================================
// Class to contain data about a plane.
//
// The plane is described as a normal {A,B,C} and a D plane coefficient
// making the following equation true: Ax + By + Cz + D = 0.
class Plane
{
private:
// The plane's normal
Vector normal;
// The plane's D coefficient
real d;
public:
Plane(void);
Plane(const Vector &newNormal, real newD);
Plane(const Vector &point0, const Vector &point1, const Vector &point2);
Plane(const Vector &normal, const Vector &pointOnPlane);
void set(const Vector &newNormal, real newD);
void set(const Vector &point0, const Vector &point1, const Vector &point2);
void set(const Vector &newNormal, const Vector &pointOnPlane);
void set(const Plane &other, const Transform &trans);
void transform (const Transform &trans);
void transform_p2l(const Transform &trans);
const Vector &getNormal(void) const;
const real getD(void) const;
real computeDistanceTo(const Vector &point) const;
bool findIntersection(const Vector &point0, const Vector &point1) const;
bool findIntersection(const Vector &point0, const Vector &point1, Vector &intersection) const;
bool findIntersection(const Vector &point0, const Vector &point1, Vector &intersection, real &t) const;
bool findIntersection(const Vector &point0, const Vector &point1, real &t) const;
bool findDirectedIntersection(const Vector &point0, const Vector &point1) const;
bool findDirectedIntersection(const Vector &point0, const Vector &point1, Vector &intersection) const;
bool findDirectedIntersection(const Vector &point0, const Vector &point1, Vector &intersection, real &t) const;
bool findDirectedIntersection(const Vector &point0, const Vector &point1, real &t) const;
const Vector project(const Vector& point) const;
static real computeD(const Vector &normal, const Vector &point);
};
// ======================================================================
// Compute the plane d coefficient
//
// Return value:
//
// Plane D coefficient
//
// Remarks:
//
// d = -(ax + by + cz) = -(normal dot point)
inline real Plane::computeD(const Vector &norm, const Vector &point)
{
return -norm.dot(point);
}
// ----------------------------------------------------------------------
/**
* Construct a plane.
*
* The default plane will be pointed down the position Z axis, and be located
* at the origin.
*/
inline Plane::Plane(void)
: normal(Vector::unitZ),
d(CONST_REAL(0))
{
}
// ----------------------------------------------------------------------
/**
* Construct a plane.
*
* This routine constructs a plane with the specified normal and D-plane coefficient.
*
* @param newNormal [IN] Normal for the plane
* @param newD [IN] D-plane coefficient for the plane
*/
inline Plane::Plane(const Vector &newNormal, real newD)
: normal(newNormal),
d(newD)
{
}
// ----------------------------------------------------------------------
/**
* Construct a plane.
*
* This routine constructs a plane with the specified normal. The point
* on the plane is used to calculate the D-plane coefficient.
*
* @param newNormal [IN] Normal for the plane
* @param point [IN] Point on the plane
*/
inline Plane::Plane(const Vector &newNormal, const Vector &point)
: normal(newNormal),
d(computeD(newNormal, point))
{
}
// ----------------------------------------------------------------------
/**
* Set a plane.
*
* This routine sets the plane to have the specified normal and D-plane coefficient.
*
* @param newNormal [IN] Normal for the plane
* @param newD [IN] D-plane coefficient for the plane
*/
inline void Plane::set(const Vector &newNormal, real newD)
{
normal = newNormal;
d = newD;
}
// ----------------------------------------------------------------------
/**
* Set a plane.
*
* This routine sets the plane to have the specified normal and D-plane coefficient.
*
* @param newNormal [IN] Normal for the plane
* @param point [IN] Point on the plane
*/
inline void Plane::set(const Vector& newNormal, const Vector& point)
{
normal = newNormal;
d = computeD(normal, point);
}
// ----------------------------------------------------------------------
/**
* Compute the signed distance from the point to the plane.
*
* If the result is 0, the point is on the plane. If the result is positive,
* the point is on the front half-space of the plane. If the result is
* negative, the point is on the back half-space of the plane.
*
* @param point [IN] Point to test against the plane
* @return Signed distance from the point to the plane.
*/
inline real Plane::computeDistanceTo(const Vector &point) const
{
return normal.dot(point) + d;
}
// ----------------------------------------------------------------------
/**
* Get the plane's normal.
*
* The normal will be a unit vector pointing orthogonal to the plane.
*
* @return Normal for the plane
*/
inline const Vector &Plane::getNormal(void) const
{
return normal;
}
// ----------------------------------------------------------------------
/**
* Get the plane's D coefficient.
*
* The D coefficient if the value that makes the plane equation true,
* given XYZ as the plane's normal: X * x + Y * y + Z * z + D = 0.
* This value also represents the minimum distance from the origin to
* the plane.
*
* @return The D coefficient for the plane
*/
inline const real Plane::getD(void) const
{
return d;
}
// ----------------------------------------------------------------------
/**
* Find point projected onto the plane.
*
* @return The projected point onto the plane.
*/
inline const Vector Plane::project(const Vector &point) const
{
return point - (normal * computeDistanceTo(point));
}
// ----------------------------------------------------------------------
/**
* Set the value of this plane to be that of ther other with the specified transformation applied.
*
* @param other the other plane
* @param trans the transformation to be applied.
*/
inline void Plane::set (const Plane & other, const Transform & trans)
{
normal = other.normal;
d = other.d;
transform (trans);
}
// ======================================================================
#endif
@@ -0,0 +1,319 @@
// Polynomial solver code adapted from Graphics Gems version
// by Jochen Schwarze
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/PolySolver.h"
#include <math.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
double cuberoot( double x )
{
return ((x) > 0.0 ? pow(x, 1.0/3.0) : ((x) < 0.0 ? -pow(-x, 1.0/3.0) : 0.0));
}
int PolySolver::solveQuadratic( double const c[3], double s[2] )
{
double p, q, D;
/* normal form: x^2 + px + q = 0 */
p = c[ 1 ] / (2 * c[ 2 ]);
q = c[ 0 ] / c[ 2 ];
D = p * p - q;
if (D < 0)
{
return 0;
}
else
{
double sqrt_D = sqrt(D);
s[ 0 ] = sqrt_D - p;
s[ 1 ] = - sqrt_D - p;
return 2;
}
}
int PolySolver::solveCubic( double const c[4], double s[3] )
{
int i, num;
double sub;
double A, B, C;
double sq_A, p, q;
double cb_p, D;
/* normal form: x^3 + Ax^2 + Bx + C = 0 */
A = c[ 2 ] / c[ 3 ];
B = c[ 1 ] / c[ 3 ];
C = c[ 0 ] / c[ 3 ];
/* substitute x = y - A/3 to eliminate quadric term:
x^3 +px + q = 0 */
sq_A = A * A;
p = (1.0/3) * (- (1.0/3) * sq_A + B);
q = (1.0/2) * (((2.0/27) * A * sq_A - ((1.0/3) * A * B)) + C);
/* use Cardano's formula */
cb_p = p * p * p;
D = q * q + cb_p;
if (D < 0) /* Casus irreducibilis: three real solutions */
{
double phi = (1.0/3) * acos(-q / sqrt(-cb_p));
double t = 2 * sqrt(-p);
s[ 0 ] = t * cos(phi);
s[ 1 ] = - t * cos(phi + M_PI / 3);
s[ 2 ] = - t * cos(phi - M_PI / 3);
num = 3;
}
else /* one real solution */
{
double sqrt_D = sqrt(D);
double u = cuberoot(sqrt_D - q);
double v = - cuberoot(sqrt_D + q);
s[ 0 ] = u + v;
num = 1;
}
/* resubstitute */
sub = (1.0/3) * A;
for (i = 0; i < num; ++i)
s[ i ] -= sub;
return num;
}
double cubicError = 0.0f;
double cleanedCubicError = 0.0f;
double quarticError = 0.0f;
double cleanedQuarticError = 0.0f;
double evaluateCubic( double x, const double c[4] )
{
return ((x*c[3] + c[2]) * x + c[1]) * x + c[0];
}
double evaluateCubicDerivative ( double x, const double c[4] )
{
return (3.0*x + 2.0*c[2]) * x + c[1];
}
double cleanCubicRoot( double x, const double c[4] )
{
double e;
e = evaluateCubic(x,c);
if(fabs(e) > cubicError) cubicError = e;
// ----------
// for(int i = 0; i < 10; i++)
{
e = evaluateCubic(x,c);
e *= 0.8;
double d = evaluateCubicDerivative(x,c);
if(d != 0.0)
{
x = x - e/d;
}
}
// ----------
e = evaluateCubic(x,c);
if(fabs(e) > cleanedCubicError) cleanedCubicError = e;
return x;
}
double evaluateQuartic( double x, const double c[5] )
{
return (((x*c[4] + c[3]) * x + c[2]) * x + c[1]) * x + c[0];
}
double evaluateQuarticDerivative ( double x, const double c[5] )
{
return ((4.0*x*c[4] + 3.0*c[3]) * x + 2.0*c[2]) * x + c[1];
}
double cleanQuarticRoot( double x, const double c[4] )
{
double e;
e = evaluateQuartic(x,c);
if(fabs(e) > quarticError) quarticError = e;
// ----------
// for(int i = 0; i < 10; i++)
{
e = evaluateQuartic(x,c);
e *= 0.8;
double d = evaluateQuarticDerivative(x,c);
if(d != 0.0)
{
x = x - e/d;
}
}
// ----------
e = evaluateQuartic(x,c);
if(fabs(e) > cleanedQuarticError) cleanedQuarticError = e;
return x;
}
#ifdef WIN32
#define isnan(a) _isnan(a)
#endif
int PolySolver::solveQuartic( const double c[5], double s[4] )
{
double a3 = c[3] / c[4];
double a2 = c[2] / c[4];
double a1 = c[1] / c[4];
double a0 = c[0] / c[4];
// ----------
// solve the resolvent cubic to get a real root
double y1 = 1.0f;
{
double c[4];
c[3] = 1.0;
c[2] = -a2;
c[1] = (a1*a3) - (4.0)*(a0);
c[0] = (4.0)*(a2*a0) - (a1*a1) - (a3*a3*a0);
double s[3];
int nRoots = PolySolver::solveCubic(c,s);
for(int i = 0; i < nRoots; i++)
{
if(s[i] == s[i])
{
// root is real
y1 = cleanCubicRoot( s[i], c );
break;
}
}
}
// ----------
// use the root to find the roots of the quadric
double t1 = (1.0/4.0)*(a3*a3) - a2 + y1;
double R = sqrt(t1);
double D;
if(R == 0.0)
{
double t1 = (y1*y1) - (4.0)*(a0);
double t2 = sqrt(t1);
double t3 = (3.0/4.0)*(a3*a3) - (2.0)*(a2) + (2.0)*t2;
D = sqrt(t3);
}
else
{
double t1 = (4.0)*(a3*a2) - (8.0)*(a1) - (a3*a3*a3);
double t2 = t1 / (4.0 * R);
double t3 = (3.0/4.0)*(a3*a3) - (R*R) - (2.0)*(a2) + t2;
D = sqrt(t3);
}
double E;
if(R == 0.0)
{
double t1 = (y1*y1) - (4.0)*(a0);
double t2 = sqrt(t1);
double t3 = (3.0/4.0)*(a3*a3) - (2.0)*(a2) - (2.0)*(t2);
E = sqrt(t3);
}
else
{
double t1 = (4.0)*(a3*a2) - (8.0)*(a1) - (a3*a3*a3);
double t2 = t1 / (4.0 * R);
double t3 = (3.0/4.0)*(a3*a3) - (R*R) - (2.0)*(a2) - t2;
E = sqrt(t3);
}
static const double nan = sqrt(-1.0f);
if (isnan(D))
{
s[0] = nan;
s[1] = nan;
}
else
{
s[0] = (-1.0/4.0)*a3 + (1.0/2.0)*R + (1.0/2.0)*D;
s[1] = (-1.0/4.0)*a3 + (1.0/2.0)*R - (1.0/2.0)*D;
}
if (isnan(E))
{
s[2] = nan;
s[3] = nan;
}
else
{
s[2] = (-1.0/4.0)*a3 - (1.0/2.0)*R + (1.0/2.0)*E;
s[3] = (-1.0/4.0)*a3 - (1.0/2.0)*R - (1.0/2.0)*E;
}
/*
// Perform one step of a Newton iteration in order to minimize round-off errors
int i;
for(i = 0; i < 4; i++)
{
s[i] = cleanQuarticRoot(s[i],c);
}
*/
return 4;
}
@@ -0,0 +1,26 @@
// ======================================================================
//
// PolySolver.h
// copyright (c) 2001 Sony Online Entertainment
//
// ----------------------------------------------------------------------
#ifndef INCLUDED_PolySolver_H
#define INCLUDED_PolySolver_H
// ----------------------------------------------------------------------
class PolySolver
{
public:
static int solveQuadratic ( double const c[3], double r[2] );
static int solveCubic ( double const c[4], double r[3] );
static int solveQuartic ( double const c[5], double r[4] );
};
// ----------------------------------------------------------------------
#endif // #ifndef INCLUDED_PolySolver_H
@@ -0,0 +1,146 @@
// ======================================================================
//
// PositionVertexIndexer.cpp
// copyright 2002, Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/PositionVertexIndexer.h"
#include "sharedFoundation/Crc.h"
#include <algorithm>
#include <limits>
#include <vector>
// ======================================================================
namespace PositionVertexIndexerNamespace
{
size_t const s_bucketSize = 149;
}
using namespace PositionVertexIndexerNamespace;
// ======================================================================
PositionVertexIndexer::PositionVertexIndexer() :
m_vertices(new VectorVector),
m_indexMap(new VertexIndexMap(s_bucketSize))
{
}
// ----------------------------------------------------------------------
PositionVertexIndexer::~PositionVertexIndexer()
{
delete m_vertices;
m_vertices = 0;
delete m_indexMap;
m_indexMap = 0;
}
// ----------------------------------------------------------------------
void PositionVertexIndexer::reserve(int const numberOfVertices)
{
DEBUG_FATAL(numberOfVertices < 0, ("PositionVertexIndexer::reserve: numberOfVertices < 0"));
m_vertices->reserve(static_cast<size_t>(numberOfVertices));
}
// ----------------------------------------------------------------------
int PositionVertexIndexer::addVertex(Vector const & vertex)
{
uint32 const key = Crc::calculate(&vertex,sizeof(vertex));
std::pair<VertexIndexMap::iterator, VertexIndexMap::iterator> collisions = m_indexMap->equal_range(key);
bool insertVertex = true;
int index = 0;
if (collisions.first != m_indexMap->end())
{
// set insertVertex to false.
insertVertex = false;
// if so, look for collisions.
for (; collisions.first != collisions.second; ++collisions.first)
{
index = collisions.first->second;
Vector const & existingVertex = (*m_vertices)[static_cast<size_t>(index)];
// if we find a collision, insert the vertex instead of returning the existing index.
if (vertex != existingVertex)
{
insertVertex = true;
break;
}
}
}
if (insertVertex)
{
// add a unique vertex to the map.
// get current index.
index = static_cast<int>(m_vertices->size());
// add to list.
m_vertices->push_back(vertex);
// insert into map.
IGNORE_RETURN(m_indexMap->insert(std::make_pair(key, index)));
}
return index;
}
// ----------------------------------------------------------------------
int PositionVertexIndexer::getNumberOfVertices() const
{
return static_cast<int>(m_vertices->size());
}
// ----------------------------------------------------------------------
void PositionVertexIndexer::clear()
{
m_vertices->clear();
m_indexMap->clear();
}
// ----------------------------------------------------------------------
Vector const & PositionVertexIndexer::getVertex(int const index) const
{
VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfVertices());
return (*m_vertices)[static_cast<size_t>(index)];
}
// ----------------------------------------------------------------------
Vector & PositionVertexIndexer::getVertex(int const index)
{
VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfVertices());
return (*m_vertices)[static_cast<size_t>(index)];
}
// ----------------------------------------------------------------------
PositionVertexIndexer::VectorVector const & PositionVertexIndexer::getVertices() const
{
return *m_vertices;
}
// ----------------------------------------------------------------------
PositionVertexIndexer::VectorVector & PositionVertexIndexer::getVertices()
{
return *m_vertices;
}
// ======================================================================
@@ -0,0 +1,53 @@
// ======================================================================
//
// PositionVertexIndexer.h
// Copyright 2004, Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_PositionVertexIndexer_H
#define INCLUDED_PositionVertexIndexer_H
// ======================================================================
#include "sharedMath/Vector.h"
#include <hash_map>
// ======================================================================
class PositionVertexIndexer
{
public:
typedef stdvector<Vector>::fwd VectorVector;
PositionVertexIndexer();
~PositionVertexIndexer();
void clear();
void reserve(int numberOfVertices);
int addVertex(Vector const & vertex);
int getNumberOfVertices() const;
Vector const & getVertex(int index) const;
VectorVector const & getVertices() const;
Vector & getVertex(int index);
VectorVector & getVertices();
private:
PositionVertexIndexer(PositionVertexIndexer const &);
PositionVertexIndexer & operator=(PositionVertexIndexer const &);
private:
typedef std::hash_multimap<uint32 /*crc*/, int /*index*/> VertexIndexMap;
VectorVector * m_vertices;
VertexIndexMap * m_indexMap;
};
// ======================================================================
#endif
@@ -0,0 +1,356 @@
// ======================================================================
//
// Quaternion.cpp
// Portions Copyright 1999, Bootprint Entertainment
// Portions Copyright 2001, 2002 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Quaternion.h"
#include "sharedMath/Transform.h"
#include "sharedMath/Vector.h"
// ======================================================================
namespace QuaternionNamespace
{
float const s_quatEpsilon = 1.19209e-007f;
float const s_quatEqualityEpsilon = 1e-027f;
}
using namespace QuaternionNamespace;
// ======================================================================
const Quaternion Quaternion::identity;
// ======================================================================
Quaternion::Quaternion(void) :
w(1.0f),
x(0.0f),
y(0.0f),
z(0.0f)
{
}
// ----------------------------------------------------------------------
/**
* construct a quaternion representing the rotational orientation specified
* by the given transform.
*/
Quaternion::Quaternion(const Transform &transform) :
w(1.0f),
x(0.0f),
y(0.0f),
z(0.0f)
{
const float trace = transform.matrix[0][0] + transform.matrix[1][1] + transform.matrix[2][2] + 1.0f;
if (trace >= 2.0f)
{
const float sqrtTrace = sqrt(trace);
w = sqrtTrace * 0.5f;
const float d = 0.5f / sqrtTrace;
x = (transform.matrix[2][1] - transform.matrix[1][2]) * d;
y = (transform.matrix[0][2] - transform.matrix[2][0]) * d;
z = (transform.matrix[1][0] - transform.matrix[0][1]) * d;
}
else
{
int i = 0, j = 1, k = 2;
if (transform.matrix[1][1] > transform.matrix[i][i])
i = 1, j = 2, k = 0;
if (transform.matrix[2][2] > transform.matrix[i][i])
i = 2, j = 0, k = 1;
// super hack for efficiency
float *v = &x;
v[i] = sqrt(((transform.matrix[i][i] - transform.matrix[j][j]) - transform.matrix[k][k]) + 1.0f) * 0.5f; //lint !e662 !e661
const float d = 1.0f / (4.0f * v[i]); //lint !e662 !e661
v[j] = (transform.matrix[j][i] + transform.matrix[i][j]) * d;
v[k] = (transform.matrix[k][i] + transform.matrix[i][k]) * d; //lint !e661
w = (transform.matrix[k][j] - transform.matrix[j][k]) * d;
}
}
// ----------------------------------------------------------------------
/**
* construct a quaternion representing the orientation specified by spinning
* 'angle' number of radians around unit vector 'vector'.
*
* Make sure 'vector' is normalized. This routine will not normalize it
* for you.
*
* @param angle [IN] angle to spin around vector (in radians)
* @param vector [IN] vector around which angle is spun (must be normalized)
*/
Quaternion::Quaternion(float angle, const Vector &vector) :
w(0.0f),
x(0.0f),
y(0.0f),
z(0.0f)
{
// -TRF- do a DEBUG_FATAL check on magnitude to ensure it is nearly 1.0
const float halfAngle = 0.5f * angle;
const float sinHalfAngle = sin(halfAngle);
w = cos(halfAngle);
x = vector.x * sinHalfAngle;
y = vector.y * sinHalfAngle;
z = vector.z * sinHalfAngle;
}
// ----------------------------------------------------------------------
Quaternion::Quaternion(float newW, float newX, float newY, float newZ) :
w(newW),
x(newX),
y(newY),
z(newZ)
{
}
// ----------------------------------------------------------------------
Quaternion::~Quaternion(void)
{
}
// ----------------------------------------------------------------------
void Quaternion::getTransform(Transform *transform) const
{
NOT_NULL(transform);
getTransformPreserveTranslation(transform);
transform->setPosition_p(Vector::zero);
}
// ----------------------------------------------------------------------
void Quaternion::getTransformPreserveTranslation(Transform *transform) const
{
DEBUG_FATAL(!transform, ("null transform arg"));
if ((w + s_quatEqualityEpsilon) < 1.f)
{
const float yyTimes2 = y * y * 2.0f;
const float zzTimes2 = z * z * 2.0f;
const float xyTimes2 = x * y * 2.0f;
const float wzTimes2 = w * z * 2.0f;
const float xzTimes2 = x * z * 2.0f;
const float wyTimes2 = w * y * 2.0f;
transform->matrix[0][0] = (1.0f - yyTimes2) - zzTimes2;
transform->matrix[0][1] = xyTimes2 - wzTimes2;
transform->matrix[0][2] = xzTimes2 + wyTimes2;
const float xxTimes2 = x * x * 2.0f;
const float yzTimes2 = y * z * 2.0f;
const float wxTimes2 = w * x * 2.0f;
transform->matrix[1][0] = xyTimes2 + wzTimes2;
transform->matrix[1][1] = (1.0f - xxTimes2) - zzTimes2;
transform->matrix[1][2] = yzTimes2 - wxTimes2;
transform->matrix[2][0] = xzTimes2 - wyTimes2;
transform->matrix[2][1] = yzTimes2 + wxTimes2;
transform->matrix[2][2] = (1.0f - xxTimes2) - yyTimes2;
}
else
{
transform->resetRotate_l2p();
}
}
// ----------------------------------------------------------------------
const Quaternion Quaternion::operator -(void) const
{
return Quaternion(-w, -x, -y, -z);
}
// ----------------------------------------------------------------------
Quaternion &Quaternion::operator +=(const Quaternion &rhs)
{
w += rhs.w;
x += rhs.x;
y += rhs.y;
z += rhs.z;
return *this;
}
// ----------------------------------------------------------------------
Quaternion &Quaternion::operator -=(const Quaternion &rhs)
{
w -= rhs.w;
x -= rhs.x;
y -= rhs.y;
z -= rhs.z;
return *this;
}
// ----------------------------------------------------------------------
Quaternion &Quaternion::operator *=(const Quaternion &rhs)
{
// not effective to define this here since we'd need to save all the values
// as we computed them anyway.
*this = Quaternion(*this) * rhs;
return *this;
} //lint !e1762 // function could be const - huh? no it couldn't...
// ----------------------------------------------------------------------
float Quaternion::getMagnitudeSquared(void) const
{
return w * w + x * x + y * y + z * z;
}
// ----------------------------------------------------------------------
void Quaternion::normalize(void)
{
float reciprocalMag = 1.0f / sqrt( x * x + y * y + z * z + w * w );
x *= reciprocalMag;
y *= reciprocalMag;
z *= reciprocalMag;
w *= reciprocalMag;
}
// ----------------------------------------------------------------------
/**
* perform spherical linear interpolation between this quaternion and
* 'other' quaternion.
*
* This routine performs a spherical linear interpolation between the
* orientation represented by this quaternion and the orientation
* represented by 'other' quaternion. 'fractionOfOther' specifies
* the fraction of 'other' blended with this quaternion. A fraction
* of 0.0 indicates only this quaternion, whereas a fraction of 1.0
* indicates only the 'other' quaternion. Values in between represent
* a spherical linear interpolation between the two quaternions.
*
* Although not a strict requirement, 'fractionOfOther' typically should
* be restricted to the range zero to one.
*/
const Quaternion Quaternion::slerp(const Quaternion & otherOriginal, float fractionOfOther) const
{
// rls - check ensure interpolation using the shortest path around the "hypersphere."
float const dotOriginal = dot(otherOriginal);
Quaternion const otherClosest(dotOriginal < 0.0f ? -otherOriginal : otherOriginal);
float const cosTheta = dot(otherClosest);
if ((1.0f + cosTheta) > s_quatEpsilon)
{
float c1, c2;
// usual case. this means sin theta has enough value.
if ((1.0f - cosTheta) > s_quatEpsilon)
{
// usual
float const theta = acos(cosTheta);
float const ooSinTheta = 1.0f / sin(theta); // rls - multiply instead of divide.
float const fractionTimesTheta = fractionOfOther * theta;
c1 = sin(theta - fractionTimesTheta) * ooSinTheta;
c2 = sin(fractionTimesTheta) * ooSinTheta;
}
else
{
// ends very close
c1 = 1.0f - fractionOfOther;
c2 = fractionOfOther;
}
return Quaternion(
c1 * w + c2 * otherClosest.w,
c1 * x + c2 * otherClosest.x,
c1 * y + c2 * otherClosest.y,
c1 * z + c2 * otherClosest.z
);
}
// ends nearly opposite
float const fractionTimesTheta = PI * fractionOfOther;
float const c1 = sin(PI_OVER_2 - fractionTimesTheta);
float const c2 = sin(fractionTimesTheta);
return Quaternion(
c1 * w + c2 * z,
c1 * x - c2 * y,
c1 * y + c2 * x,
c1 * z - c2 * w
);
}
// ----------------------------------------------------------------------
const Quaternion Quaternion::operator +(const Quaternion &rhs) const
{
return Quaternion(w + rhs.w, x + rhs.x, y + rhs.y, z + rhs.z);
}
// ----------------------------------------------------------------------
const Quaternion Quaternion::operator -(const Quaternion &rhs) const
{
return Quaternion(w - rhs.w, x - rhs.x, y - rhs.y, z - rhs.z);
}
// ----------------------------------------------------------------------
const Quaternion Quaternion::operator *(const Quaternion &rhs) const
{
// rls - do not multiply by identity quaternions.
if ((rhs.w + s_quatEqualityEpsilon) >= 1.f)
{
return *this; // return *this because the other is an identity quaternion.
}
else if ((w + s_quatEqualityEpsilon) >= 1.f)
{
return rhs; // return rhs because this quaternion is an identity quaternion.
}
// Equation from CRC Concise Encyclopedia of Mathematics, p 1494, equations 24 and 25
//
// Assume quaternion of form (a1,A) = a1 + a2*i + a3*j + a4*k
// (that is, A = [a2 a3 a4]T)
// then (s1,V1) * (s2,V2) = (s1*s2 - V1 <dot> V2, s1*V2 + s2*V1 + V1 <cross> V2)
// where <dot> = dot product binary operator and
// <cross> = cross product binary operator
//
// lhs * rhs
//
// w = w * rhs.w - (x * rhs.x + y * rhs.y + z * rhs.z)
// x = w * rhs.x + rhs.w * x + (y * rhs.z - z * rhs.y)
// y = w * rhs.y + rhs.w * y + (z * rhs.x - x * rhs.z)
// z = w * rhs.z + rhs.w * z + (x * rhs.y - y * rhs.x)
return Quaternion(
w * rhs.w - (x * rhs.x + y * rhs.y + z * rhs.z),
w * rhs.x + rhs.w * x + (y * rhs.z - z * rhs.y),
w * rhs.y + rhs.w * y + (z * rhs.x - x * rhs.z),
w * rhs.z + rhs.w * z + (x * rhs.y - y * rhs.x)
);
}
// ----------------------------------------------------------------------
void Quaternion::debugDump() const
{
DEBUG_REPORT_LOG(true, ("[w=%g,x=%g,y=%g,z=%g]\n", w, x, y, z));
}
// ======================================================================
@@ -0,0 +1,108 @@
// ======================================================================
//
// Quaternion.h
// Portions Copyright 1999, Bootprint Entertainment
// Portions Copyright 2001, 2002 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_Quaternion_H
#define INCLUDED_Quaternion_H
// ======================================================================
class Transform;
class Vector;
// ======================================================================
class Quaternion
{
friend class Iff;
public:
static const Quaternion identity;
public:
real w;
real x;
real y;
real z;
public:
Quaternion(void);
explicit Quaternion(const Transform &transform);
Quaternion(real angle, const Vector &vector);
Quaternion(real newW, real newX, real newY, real newZ);
~Quaternion(void);
bool operator ==(const Quaternion &rhs);
bool operator !=(const Quaternion &rhs);
const Quaternion operator -(void) const;
Quaternion &operator +=(const Quaternion &rhs);
Quaternion &operator -=(const Quaternion &rhs);
Quaternion &operator *=(const Quaternion &rhs);
const Quaternion operator +(const Quaternion &rhs) const;
const Quaternion operator -(const Quaternion &rhs) const;
const Quaternion operator *(const Quaternion &rhs) const;
void getTransform(Transform *transform) const;
void getTransformPreserveTranslation(Transform *transform) const;
real getMagnitudeSquared(void) const;
const Quaternion slerp(const Quaternion &other, real fractionOfOther) const;
void normalize(void);
Quaternion getComplexConjugate() const;
void debugDump() const;
real dot(Quaternion const & rhs) const;
};
// ======================================================================
/**
* Retrieve the complex conjugate of this Quaternion instance.
*
* When a Quaternion has a unit length Vector, the complex conjugate
* is equivalent to the inverse. This is similar to a pure rotation
* matrix, which has a simple inverse equivalent to the transpose of
* the matrix.
*
* @return
*/
inline Quaternion Quaternion::getComplexConjugate() const
{
return Quaternion(w, -x, -y, -z);
}
// ----------------------------------------------------------------------
inline bool Quaternion::operator ==(const Quaternion &rhs)
{
return (w == rhs.w && x == rhs.x && y == rhs.y && z == rhs.z);
}
// ----------------------------------------------------------------------
inline bool Quaternion::operator !=(const Quaternion &rhs)
{
return !(*this == rhs);
}
inline real Quaternion::dot(Quaternion const & rhs) const
{
return w * rhs.w + x * rhs.x + y * rhs.y + z * rhs.z;
}
// ======================================================================
#endif
@@ -0,0 +1,98 @@
//===================================================================
//
// Rectangle2d.cpp
// asommers 7-26-99
//
// copyright 1999, bootprint entertainment
// copyright 2001, sony online entertainment
//
//===================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Rectangle2d.h"
#include "sharedMath/Line2d.h"
#include "sharedMath/Vector2d.h"
#include <algorithm>
//===================================================================
inline bool WithinRange(float rangeMin, float const value, float rangeMax)
{
if (rangeMin > rangeMax)
std::swap(rangeMin, rangeMax);
return (value >= rangeMin) && (value <= rangeMax);
}
//===================================================================
const Vector2d Rectangle2d::getCenter () const
{
Vector2d tmp;
tmp.x = x0 + getWidth () * 0.5f;
tmp.y = y0 + getHeight () * 0.5f;
return tmp;
}
//-------------------------------------------------------------------
bool Rectangle2d::isWithin (const Vector2d& point) const
{
return isWithin (point.x, point.y);
}
//-------------------------------------------------------------------
void Rectangle2d::expand (const Vector2d& point)
{
expand (point.x, point.y);
}
//-------------------------------------------------------------------
void Rectangle2d::translate (const Vector2d& point)
{
translate (point.x, point.y);
}
//-------------------------------------------------------------------
void Rectangle2d::scale (const float scalar)
{
const Vector2d center = getCenter ();
x0 = (x0 - center.x) * scalar + center.x;
y0 = (y0 - center.y) * scalar + center.y;
x1 = (x1 - center.x) * scalar + center.x;
y1 = (y1 - center.y) * scalar + center.y;
}
//-------------------------------------------------------------------
bool Rectangle2d::intersects (Line2d const & line) const
{
Vector2d intersection;
Vector2d const v0(x0, y0);
Vector2d const v1(x1, y0);
if (line.findIntersection(v0, v1, intersection) && WithinRange(v0.x, intersection.x, v1.x) && WithinRange(v0.y, intersection.y, v1.y))
return true;
Vector2d const v2(x1, y1);
if (line.findIntersection(v1, v2, intersection) && WithinRange(v1.x, intersection.x, v2.x) && WithinRange(v1.y, intersection.y, v2.y))
return true;
Vector2d const v3(x0, y1);
if (line.findIntersection(v2, v3, intersection) && WithinRange(v2.x, intersection.x, v3.x) && WithinRange(v2.y, intersection.y, v3.y))
return true;
if (line.findIntersection(v3, v0, intersection) && WithinRange(v3.x, intersection.x, v0.x) && WithinRange(v3.y, intersection.y, v0.y))
return true;
return false;
}
//===================================================================
@@ -0,0 +1,208 @@
//
// Rectangle2d.h
// asommers 7-26-99
//
// copyright 1999, bootprint entertainment
// copyright 2001, sony online entertainment
//
//-------------------------------------------------------------------
#ifndef INCLUDED_Rectangle2d_H
#define INCLUDED_Rectangle2d_H
//-------------------------------------------------------------------
class Line2d;
class Vector2d;
//-------------------------------------------------------------------
class Rectangle2d
{
public:
//-- lower left
float x0;
float y0;
//-- upper right
float x1;
float y1;
public:
Rectangle2d ();
Rectangle2d (float newX0, float newY0, float newX1, float newY1);
~Rectangle2d ();
void set (float newX0, float newY0, float newX1, float newY1);
float getWidth () const;
float getHeight () const;
const Vector2d getCenter () const;
bool isWithin (float x, float y) const;
bool isWithin (const Vector2d& point) const;
bool isVector2d () const;
void expand (float x, float y);
void expand (const Vector2d& point);
void expand (const Rectangle2d& rectangle);
void translate (float x, float y);
void translate (const Vector2d& point);
void scale (float scalar);
bool intersects (const Rectangle2d& other) const;
bool contains (Rectangle2d const & other) const;
bool intersects (Line2d const & line) const;
bool operator== (const Rectangle2d& rhs) const;
bool operator!= (const Rectangle2d& rhs) const;
};
//-------------------------------------------------------------------
inline Rectangle2d::Rectangle2d () :
x0 (0),
y0 (0),
x1 (0),
y1 (0)
{
}
//-------------------------------------------------------------------
inline Rectangle2d::Rectangle2d (const float newX0, const float newY0, const float newX1, const float newY1) :
x0 (newX0),
y0 (newY0),
x1 (newX1),
y1 (newY1)
{
}
//-------------------------------------------------------------------
inline Rectangle2d::~Rectangle2d ()
{
}
//-------------------------------------------------------------------
inline void Rectangle2d::set (const float newX0, const float newY0, const float newX1, const float newY1)
{
x0 = newX0;
y0 = newY0;
x1 = newX1;
y1 = newY1;
}
//-------------------------------------------------------------------
inline float Rectangle2d::getWidth () const
{
return abs(x1 - x0);
}
//-------------------------------------------------------------------
inline float Rectangle2d::getHeight () const
{
return abs(y1 - y0);
}
//-------------------------------------------------------------------
inline bool Rectangle2d::isWithin (const float x, const float y) const
{
if (x0 < x1)
if (y0 < y1)
return
WithinRangeInclusiveInclusive (x0, x, x1) &&
WithinRangeInclusiveInclusive (y0, y, y1);
else
return
WithinRangeInclusiveInclusive (x0, x, x1) &&
WithinRangeInclusiveInclusive (y1, y, y0);
else
if (y0 < y1)
return
WithinRangeInclusiveInclusive (x1, x, x0) &&
WithinRangeInclusiveInclusive (y0, y, y1);
else
return
WithinRangeInclusiveInclusive (x1, x, x0) &&
WithinRangeInclusiveInclusive (y1, y, y0);
}
//-------------------------------------------------------------------
inline bool Rectangle2d::isVector2d () const
{
return x0 == x1 && y0 == y1;
}
//-------------------------------------------------------------------
inline void Rectangle2d::expand (const float x, const float y)
{
if (x < x0)
x0 = x;
if (y < y0)
y0 = y;
if (x > x1)
x1 = x;
if (y > y1)
y1 = y;
}
//-------------------------------------------------------------------
inline void Rectangle2d::expand (const Rectangle2d& rectangle)
{
expand (rectangle.x0, rectangle.y0);
expand (rectangle.x1, rectangle.y0);
expand (rectangle.x0, rectangle.y1);
expand (rectangle.x1, rectangle.y1);
}
//-------------------------------------------------------------------
inline void Rectangle2d::translate (const float x, const float y)
{
x0 += x;
y0 += y;
x1 += x;
y1 += y;
}
//-------------------------------------------------------------------
inline bool Rectangle2d::intersects (const Rectangle2d& other) const
{
return !(x1 < other.x0 || x0 > other.x1 || y1 < other.y0 || y0 > other.y1);
}
//-------------------------------------------------------------------
inline bool Rectangle2d::contains (Rectangle2d const & other) const
{
return other.x0 >= x0 && other.x1 <= x1 && other.y0 >= y0 && other.y1 <= y1;
}
//-------------------------------------------------------------------
inline bool Rectangle2d::operator== (const Rectangle2d& rhs) const
{
return x0 == rhs.x0 && x1 == rhs.x1 && y0 == rhs.y0 && y1 == rhs.y1;
}
//-------------------------------------------------------------------
inline bool Rectangle2d::operator!= (const Rectangle2d& rhs) const
{
return !operator== (rhs);
}
//-------------------------------------------------------------------
#endif
@@ -0,0 +1,36 @@
// ======================================================================
//
// SetupSharedMath.cpp
// Copyright 2002 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/SetupSharedMath.h"
#include "sharedMath/ConfigSharedMath.h"
#include "sharedMath/CompressedQuaternion.h"
#include "sharedMath/PaletteArgb.h"
#include "sharedMath/PaletteArgbList.h"
#include "sharedMath/Transform.h"
#include "sharedDebug/InstallTimer.h"
// ======================================================================
void SetupSharedMath::install()
{
InstallTimer const installTimer("SetupSharedMath::install");
ConfigSharedMath::install();
//-- install palette support
PaletteArgb::install();
PaletteArgbList::install();
// @todo don't bother installing this on the servers; it's unnecessary.
CompressedQuaternion::install();
Transform::install();
}
// ======================================================================
@@ -0,0 +1,24 @@
// ======================================================================
//
// SetupSharedMath.h
// Copyright 2002 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_SetupSharedMath_H
#define INCLUDED_SetupSharedMath_H
// ======================================================================
class SetupSharedMath
{
public:
static void install();
};
// ======================================================================
#endif
@@ -0,0 +1,41 @@
// SpatialSubdivision.cpp
// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved.
// Author: Justin Randall
//-----------------------------------------------------------------------
#pragma warning ( disable : 4514 ) // unreferenced inline function has been removed
#include "sharedMath/FirstSharedMath.h"
#include "SpatialSubdivision.h"
//-----------------------------------------------------------------------
SpatialSubdivisionHandle::SpatialSubdivisionHandle()
{
}
//-----------------------------------------------------------------------
SpatialSubdivisionHandle::SpatialSubdivisionHandle(const SpatialSubdivisionHandle &)
{
}
//-----------------------------------------------------------------------
SpatialSubdivisionHandle::~SpatialSubdivisionHandle()
{
}
//-----------------------------------------------------------------------
SpatialSubdivisionHandle & SpatialSubdivisionHandle::operator = (const SpatialSubdivisionHandle & rhs)
{
if(this != &rhs)
{
// make assignments if right hand side is not this instance
}
return *this;
}
//-----------------------------------------------------------------------
@@ -0,0 +1,124 @@
// SpatialSubdivision.h
// copyright 2001 Sony Online Entertainment
// Author: Justin Randall
#ifndef _INCLUDED_SpatialSubdivision_H
#define _INCLUDED_SpatialSubdivision_H
//-----------------------------------------------------------------------
class Vector;
//-----------------------------------------------------------------------
/**
Helper handle to expedite operations in a particular spatial
subdivision implementation (e.g. moving an object within a Sphere or
overlapped quadrant, traversing up from a leaf in a tree structure,
etc..)
*/
class SpatialSubdivisionHandle
{
public:
SpatialSubdivisionHandle();
virtual ~SpatialSubdivisionHandle() = 0;
SpatialSubdivisionHandle(const SpatialSubdivisionHandle & source);
SpatialSubdivisionHandle & operator=(const SpatialSubdivisionHandle & source);
};
//-----------------------------------------------------------------------
/**
@brief a templatized base class for a spatially organized container.
The SpatialSubdivision template defines an interface for all
spatially organized containers. Specific implementations may
be partially templatized (specifying the extent type, for example)
while leaving other implementation details, such as ObjectType
and ExtentAccessor routines configurable per instantiation.
For example, a multiplayer game application may have ClientObject
types on the game client, which organizes data in a Quadtree, using
axis aligned bounding boxes for extent information. A game server may
have a ServerObject that defines its extent as a Sphere and
organizes objects in a SphereTree. Additionally, a game message
routing server may have ClientConnection objects that use
Sphere extents. A single SphereTree implementation derived
from the SpatialSubdivision template could be declared as:
\code
template<class ObjectType, class ExtentAccessor>
class SphereTree : public SpatialSubdivision<ObjectType, Sphere, ExtentAccessor>
\endcode
or the client Quadtree as
\code
class QuadTree : public SpatialSubdivision<ClientObject, AxisAlignedBoundingBox, ClientObject>
\endcode
There is little penalty for generalization, since the implementation
may be written very specifically for a particular application, yet
maintain a common template interface that does not rely on objects or
extents.
Because the SpatialSubdivision class is intended to be an interface
definition, it doesn't DO anything and is pure virtual.
@author Justin Randall
*/
template <class ObjectType>
class SpatialSubdivisionFilter
{
public:
virtual ~SpatialSubdivisionFilter() {}
virtual bool operator()(const ObjectType &) const=0;
};
template<class ObjectType, class ExtentType, class ExtentAccessor>
class SpatialSubdivision
{
public:
SpatialSubdivision ();
virtual ~SpatialSubdivision () = 0;
virtual SpatialSubdivisionHandle * addObject (ObjectType object) = 0;
virtual const bool canSee (SpatialSubdivisionHandle * target, const Vector & start, const float distance, const float fov=0.0f) const = 0; //lint !e1735 // virtual function has default parameter
virtual void findInRange (const Vector & origin, const float distance, typename stdvector<ObjectType>::fwd & results) const = 0;
virtual void findInRange (const Vector & origin, const float distance, const SpatialSubdivisionFilter<ObjectType> &filter, typename stdvector<ObjectType>::fwd & results) const = 0;
virtual void findOnRay (const Vector & begin, const Vector & dir, typename stdvector<ObjectType>::fwd & results) const = 0;
virtual void findOnSegment (const Vector & begin, const Vector & end, typename stdvector<ObjectType>::fwd & results) const = 0;
virtual void move (SpatialSubdivisionHandle * object) = 0;
virtual void removeObject (SpatialSubdivisionHandle * object) = 0;
private:
SpatialSubdivision & operator = (const SpatialSubdivision & rhs);
SpatialSubdivision(const SpatialSubdivision & source);
};
//-----------------------------------------------------------------------
/**
@brief construct for a SpatialSubdivision template instance.
This constructor doesn't do anything. It is present for completeness.
@author Justin Randall
*/
template<class ObjectType, class ExtentType, class ExtentAccessor>
inline SpatialSubdivision<ObjectType, ExtentType, ExtentAccessor>::SpatialSubdivision()
{
}
//-----------------------------------------------------------------------
/**
@brief destroy a SpatialSubdivision template instance
This destructor doesn't do anything. It is present for completeness.
@author Justin Randall
*/
template<class ObjectType, class ExtentType, class ExtentAccessor>
inline SpatialSubdivision<ObjectType, ExtentType, ExtentAccessor>::~SpatialSubdivision()
{
}
//-----------------------------------------------------------------------
#endif // _INCLUDED_SpatialSubdivision_H
@@ -0,0 +1,113 @@
// ======================================================================
//
// Sphere.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Sphere.h"
#include "sharedMath/Range.h"
#include "sharedMath/Circle.h"
// ======================================================================
/// Sphere centered at (0,0,0) with a radius of 0.
const Sphere Sphere::zero;
/// Sphere centered at (0,0,0) with a radius of 1.
const Sphere Sphere::unit(Vector::zero, CONST_REAL(1));
// ======================================================================
Circle Sphere::getCircle ( void ) const
{
return Circle(m_center,m_radius);
}
Range Sphere::getRangeX ( void ) const
{
return Range( m_center.x - m_radius, m_center.x + m_radius );
}
Range Sphere::getRangeY ( void ) const
{
return Range( m_center.y - m_radius, m_center.y + m_radius );
}
Range Sphere::getRangeZ ( void ) const
{
return Range( m_center.z - m_radius, m_center.z + m_radius );
}
bool Sphere::intersectsCone(Vector const & coneBase, Vector const & coneNormal, float const coneAngleRadians) const
{
float const angleSine = sinf(coneAngleRadians);
float const angleCosine = cosf(coneAngleRadians);
float const angleInverseSine = angleSine > FLT_MIN ? 1.0f / angleSine : 0.0f;
float const angleCosineSquared = sqr(angleCosine);
Vector const & vectorToSphere = m_center - coneBase;
Vector const & intersectPosition = vectorToSphere + (m_radius * angleInverseSine) * coneNormal;
float magnitudeOfIntersectionSquared = intersectPosition.magnitudeSquared();
float angleBetweenSourceAndIntersection = intersectPosition.dot(coneNormal);
bool inCone = false;
if (angleBetweenSourceAndIntersection > FLT_MIN && sqr(angleBetweenSourceAndIntersection) >= magnitudeOfIntersectionSquared * angleCosineSquared)
{
float const angleSinSquared = sqr(angleSine);
magnitudeOfIntersectionSquared = vectorToSphere.magnitudeSquared();
angleBetweenSourceAndIntersection = -vectorToSphere.dot(coneNormal);
if (angleBetweenSourceAndIntersection > FLT_MIN && sqr(angleBetweenSourceAndIntersection) >= magnitudeOfIntersectionSquared * angleSinSquared)
{
float const rangeSquared = sqr(m_radius);
inCone = magnitudeOfIntersectionSquared <= rangeSquared;
}
else
{
inCone = true;
}
}
return inCone;
}
Vector Sphere::closestPointOnSphere(Vector const & point) const
{
Vector pointOnSurface;
Vector normalToPoint(point - m_center);
if(normalToPoint.normalize())
{
pointOnSurface = m_center + (normalToPoint * m_radius);
}
else
{
pointOnSurface = m_center;
}
return pointOnSurface;
}
Vector Sphere::approximateClosestPointOnSphere(Vector const & point) const
{
Vector pointOnSurface;
Vector normalToPoint(point - m_center);
if(normalToPoint.approximateNormalize())
{
pointOnSurface = m_center + (normalToPoint * m_radius);
}
else
{
pointOnSurface = m_center;
}
return pointOnSurface;
}
// ======================================================================
@@ -0,0 +1,347 @@
// ======================================================================
//
// Sphere.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_Sphere_H
#define INCLUDED_Sphere_H
// ======================================================================
#include "sharedMath/Vector.h"
class Range;
class Circle;
// ======================================================================
/// Describes a sphere in 3d space.
class Sphere
{
public:
static const Sphere zero;
static const Sphere unit;
public:
// default destructor, copy constructor, assignment operator are all okay
Sphere();
Sphere(const Vector &center, real radius);
Sphere(real x, real y, real z, real radius);
void setCenter(real x, real y, real z);
void setCenter(const Vector &center);
void setRadius(real radius);
void set(const Vector &center, float radius);
void set(float x, float y, float z, float radius);
const Vector &getCenter() const;
const real getRadius() const;
Vector const & getAxisX ( void ) const;
Vector const & getAxisY ( void ) const;
Vector const & getAxisZ ( void ) const;
float getExtentX ( void ) const;
float getExtentY ( void ) const;
float getExtentZ ( void ) const;
Circle getCircle ( void ) const;
bool contains(const Vector &point) const;
bool contains(const Sphere &other) const;
bool intersectsLine(const Vector &startPoint, const Vector &endPoint) const;
bool intersectsLineSegment(const Vector &startPoint, const Vector &endPoint) const;
bool intersectsRay(const Vector & startPoint, const Vector & normalizedDirection) const;
bool intersectsSphere(const Sphere &other) const;
bool intersectsCone(Vector const & coneBase, Vector const & coneNormal, float coneAngleRadians) const;
Vector closestPointOnSphere(Vector const & point) const;
Vector approximateClosestPointOnSphere(Vector const & point) const;
bool operator==(const Sphere & rhs) const;
Range getRangeX ( void ) const;
Range getRangeY ( void ) const;
Range getRangeZ ( void ) const;
private:
/// Center point of the sphere.
Vector m_center;
/// Radius of the sphere.
real m_radius;
};
// ======================================================================
/**
* Construct a default sphere.
*
* The sphere will be centered at (0,0,0) and have a radius of 0.
*/
inline Sphere::Sphere()
:
m_center(),
m_radius(0)
{
}
// ----------------------------------------------------------------------
/**
* Construct a sphere.
*
* @param center The center point for the sphere.
* @param radius The radius of the sphere.
*/
inline Sphere::Sphere(const Vector &center, real radius)
:
m_center(center),
m_radius(radius)
{
WARNING_STRICT_FATAL(m_radius < 0.0f, ("Sphere has negative radius!"));
if(m_radius < 0.0f)
radius = 0.0f;
}
// ----------------------------------------------------------------------
/**
* Construct a sphere
*
* @param x The X center point of the sphere.
* @param y The Y center point of the sphere.
* @param z The Z center point of the sphere.
* @param radius The radius of the sphere.
*/
inline Sphere::Sphere(real x, real y, real z, real radius)
:
m_center(Vector(x, y, z)),
m_radius(radius)
{
WARNING_STRICT_FATAL(m_radius < 0.0f, ("Sphere has negative radius!"));
if(m_radius < 0.0f)
radius = 0.0f;
}
// ----------------------------------------------------------------------
/**
* Set the center point of the sphere.
*
* @param x The new X center point of the sphere.
* @param y The new Y center point of the sphere.
* @param z The new Z center point of the sphere.
*/
inline void Sphere::setCenter(const real x, const real y, const real z)
{
m_center.x = x;
m_center.y = y;
m_center.z = z;
}
// ----------------------------------------------------------------------
/**
* Set the center point of the sphere.
*
* @param center The new center point of the sphere.
*/
inline void Sphere::setCenter(const Vector &center)
{
m_center = center;
}
// ----------------------------------------------------------------------
/**
* Set the radius of the sphere.
*
* @param radius The new radius of the sphere.
*/
inline void Sphere::setRadius(real radius)
{
m_radius = radius;
}
// ----------------------------------------------------------------------
inline void Sphere::set(const Vector &center, const float radius)
{
m_center = center;
m_radius = radius;
}
// ----------------------------------------------------------------------
inline void Sphere::set(const float x, const float y, const float z, const float radius)
{
m_center.x = x;
m_center.y = y;
m_center.z = z;
m_radius = radius;
}
// ----------------------------------------------------------------------
/**
* Get the center point of the sphere.
*
* @return The center point of the sphere.
*/
inline const Vector &Sphere::getCenter() const
{
return m_center;
}
// ----------------------------------------------------------------------
/**
* Get the radius of the sphere.
*
* @return The radius of the sphere.
*/
inline const real Sphere::getRadius() const
{
return m_radius;
}
// ----------------------------------------------------------------------
inline Vector const & Sphere::getAxisX ( void ) const
{
return Vector::unitX;
}
inline Vector const & Sphere::getAxisY ( void ) const
{
return Vector::unitY;
}
inline Vector const & Sphere::getAxisZ ( void ) const
{
return Vector::unitZ;
}
// ----------
inline float Sphere::getExtentX ( void ) const
{
return getRadius();
}
inline float Sphere::getExtentY ( void ) const
{
return getRadius();
}
inline float Sphere::getExtentZ ( void ) const
{
return getRadius();
}
// ----------------------------------------------------------------------
/**
* Check if a point is inside the sphere
*
* @return True if the point is in the sphere, otherwise false.
*/
inline bool Sphere::contains(const Vector &point) const
{
return m_center.magnitudeBetweenSquared(point) <= sqr(m_radius);
}
// ----------------------------------------------------------------------
/**
* Check if the sphere entirely contains another sphere.
*
* @return True if the second sphere is entirely contained within the first.
*/
inline bool Sphere::contains(const Sphere &other) const
{
if (other.m_radius <= m_radius)
{
return m_center.magnitudeBetweenSquared(other.m_center) <= sqr(m_radius - other.m_radius);
}
else
return false;
}
//-----------------------------------------------------------------------
inline bool Sphere::intersectsLine(const Vector & line0, const Vector & line1) const
{
return contains(m_center.findClosestPointOnLine(line0, line1));
}
//-----------------------------------------------------------------------
inline bool Sphere::intersectsLineSegment(const Vector & startPoint, const Vector & endPoint) const
{
return contains(m_center.findClosestPointOnLineSegment(startPoint, endPoint));
}
//-----------------------------------------------------------------------
/**
@brief determine if a ray intersects a sphere
*/
inline bool Sphere::intersectsRay(const Vector & startPoint, const Vector & normalizedDirection) const
{
// If the ray starts inside the sphere,
// it MUST intersect the sphere
if(contains(startPoint))
return true;
// get the squre magnitude between the origin of the sphere
// and the start point of the ray
Vector rayStartPointToCenter = m_center - startPoint;
// project the ling segment described by the ray start point to the
// sphere origin on the ray
const float originRayDot = rayStartPointToCenter.dot(normalizedDirection);
if(originRayDot < 0.0f)
{
// Center of the sphere is 'behind' the ray, the sphere can't intersect the ray
// without containing the start point, but since it doesn't the sphere doesn't intersect
// the ray.
return false;
}
// distanceSquared - sqr(originRayDot) = squre length of the line
// segment from the sphere origin that is perpendicular to the ray.
// If that length is less than the radius, there is an intersection.
const float distanceSquared = rayStartPointToCenter.magnitudeSquared();
const float distanceToRaySquared = sqr(m_radius) - (distanceSquared - sqr(originRayDot));
return (distanceToRaySquared > 0.0f);
}
//-----------------------------------------------------------------------
inline bool Sphere::intersectsSphere(const Sphere & other) const
{
const real d = m_center.magnitudeBetweenSquared(other.getCenter());
const real r = sqr(m_radius + other.getRadius());
return d < r;
}
//----------------------------------------------------------------------
inline bool Sphere::operator==(const Sphere & rhs) const
{
return this == &rhs || (m_radius == rhs.m_radius && m_center == rhs.m_center);
}
// ======================================================================
#endif
@@ -0,0 +1,657 @@
// SphereTree.h
// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved.
// Author: Justin Randall
#ifndef _INCLUDED_SphereTree_H
#define _INCLUDED_SphereTree_H
//-----------------------------------------------------------------------
#include "sharedMath/Sphere.h"
#include "sharedMath/Capsule.h"
#include "sharedMath/SpatialSubdivision.h"
#include "sharedMath/SphereTreeNode.h"
//-----------------------------------------------------------------------
/**
@brief a templatized implementation of a sphere tree.
A SphereTree organizes data hierarchically in sphere nodes.
Sphere nodes have a containment relationship, starting from the
more general, larger sphere nodes, to smaller, more granular
nodes which contain objects. Any node may contain objects as well
as child nodes.
The tree balances itself as it discovers usable world space.
Its depth is defined by the potential worldspace covered by the tree
and the extent data of the objects contained within the tree.
The default behavior of the tree is to provide general coverage of
world space with about 32 nodes. Child nodes follow this heuristic
as items are inserted into the tree. Item extents (by default)
want to be ten times smaller than a container node's maximum extent.
If this ratio is exceeded, the object continues to fall through the
tree until a suitable leaf node is located.
These heuristics may be tweaked, but generally show good behavior,
favoring move, range, and reintegration to insertion performance.
In simulations with 1 million objects in a 16 cubic kilometer world
space, the tree provides performance of over 1,000 move operations
per millisecond.
How it works ---
INSERTING
When an object is first added to the SphereTree, it is passed to
the root node, which encompasses all world space. If the object
falls outside of the root node, the root node is expanded, and
new max sizes for child nodes are calculated to keep the tree
generally balanced for future operations. If the object extent
exceeds the ratio of object-to-leaf-max size, then the maximum
node size is again recalculated for general balancing. The first
few insertions into the tree will trigger these recalculations,
but have no effect on existing nodes.
Once the balancing calculations are done (if they were needed at
all in the first place), the root node finds a candidate child
node to accept the new object. If no candidate exists, a new
child sphere is created, and the object is passed to the child.
The child will repeat the previous step, finding candidates
(new nodes don't check, they don't have children), and passing
the object further down the tree until a suitably sized child
node contains the object.
The default behavior is to find child nodes that are a
factor of 4 times smaller with each step towards the solution
leaf node. The solution leaf must be (by default) 10 times larger
than objects it contains.
An object with a 1 meter sphere in a 16 kilometer world follows
this path: [ root -> 4k child -> 1k child -> 250 meter child ->
62 meter child ] or a depth of 4.
MOVING
When an object moves, the destination sphere is checked against
the containing node. If the real size of the containing node's
sphere can contain the object, the operation is complete.
If the real node size cannot contain the object, then a check
is made to see if the max size can contain the object. If it
can, the node is resized and the operation completes.
If the max sphere size cannot contain the object, then the
object is passed to the parent. If the object can be contained within
the parent, then a candidate target node is identified and the
object is then placed in it.
In most cases, the object stays within the real sphere size. The
next most common case is the object being contained in the container
node's max sphere. Both of these are very fast operations and
incur little cost on the system. Re-integration is slightly more
expensive but also not as common.
The worst case is that all objects warp around and must be
fully re-integrated from the root node. This is as expensive
as insertion plus the time required to traverse up the tree
and check containment candidates en route to the root node.
The worst case simulation with 1 million objects clocked move
operations at < 0.05 milliseconds (all 1 million objects moving to
origin from random locations)
FINDING IN RANGE
When the SphereTree receives a find request, it queries the root
node for all child spheres which intersect the sphere described
by the range query (location, radius). A recursive query is
made into child nodes which satisfy the intersection query,
culling more candidates as the find operations solves for all objects
intersecting the range sphere.
Find operations are faster for smaller range spheres, slower for
larger spheres, averaging thousands of results per millisecond. Most
of the time is spent filling a result vector.
OTHER NOTES
The sphere tree defines a node handle that derives from
SpatialSubdivisionHandle. Since the superclass API defines
operations in terms of a SpatialSubdivisionHandle, the sphere
tree can use this handle to go directly to a leaf node for
move operations. The application using the SphereTree merely
needs to perform all operations (except addObject) in terms
of the handle.
Tests were performed on a 700MHz P-III system with 256MB RAM running
Windows 2000. The dev environment is MSVC.
SphereTree's are succesfully in use on Linux, gcc-2.95-3 on a RedHat 6.2,
7.0 and 7.1 distributions.
DEPENDENCIES
Sphere that defines the following:
\code
void setCenter(real x, real y, real z);
void setCenter(const Vector &center);
void setRadius(real radius);
const Vector &getCenter() const;
const real getRadius() const;
bool contains(const Vector &point) const;
bool contains(const Sphere &other) const;
bool intersectsSphere(const Sphere &other) const;
bool intersectsLine(const Vector &startPoint, const Vector &endPoint) const;
bool intersectsLineSegment(const Vector &startPoint, const Vector &endPoint) const;
bool intersectsRay(const Vector & startPoint, const Vector & normalizedDirection) const;
\endcode
and Vector that defines
\code
real magnitudeSquared(void) const;
real magnitude(void) const;
real magnitudeBetween(const Vector &vector) const;
real magnitudeBetweenSquared(const Vector &vector) const;
const Vector findClosestPointOnLine(const Vector &line0, const Vector &line1) const;
const Vector findClosestPointOnLineSegment(const Vector & startPoint, const Vector & endPoint) const;
real dot(const Vector &vector) const;
\endcode
These dependencies can be satisfied with the BootPrint/Sony Online Entertainment
sharedMath library.
@see SpatialSubdivision
@see SpatialSubdivisionHandle
@author Justin Randall
*/
template<class ObjectType, class ExtentAccessor>
class SphereTree : public SpatialSubdivision<ObjectType, Sphere, ExtentAccessor>
{
public:
typedef SphereTreeNode<ObjectType, ExtentAccessor> NodeType;
SphereTree ();
~SphereTree ();
virtual SpatialSubdivisionHandle * addObject (ObjectType object);
virtual const bool canSee (SpatialSubdivisionHandle * target, const Vector & start, const float distance, const float fov=0.0f) const;
void dumpSphereTreeObjects(std::vector<ObjectType> & results) const;
void dumpSphereTree (std::vector<std::pair<ObjectType, Sphere> > & results) const;
void dumpSphereTreeNodes(std::vector<std::pair<ObjectType, Sphere> > & results) const;
void dumpSphereTreeObjs (std::vector<std::pair<ObjectType, Sphere> > & results) const;
void dumpEdgeList (std::vector<Vector> & results) const;
virtual void findInRange (const Vector & origin, const float distance, std::vector<ObjectType> & results) const;
virtual void findInRange (const Vector & origin, const float distance, std::vector<ObjectType> & results, int & testCounter) const;
virtual void findInRange (const Vector & origin, const float distance, const SpatialSubdivisionFilter<ObjectType> &filter, std::vector<ObjectType> & results) const;
virtual void findInRange (const Vector & origin, const float distance, const SpatialSubdivisionFilter<ObjectType> &filter, std::vector<ObjectType> & results, int & testCounter) const;
virtual void findOnRay (const Vector & begin, const Vector & dir, std::vector<ObjectType> & results) const;
virtual void findOnSegment (const Vector & begin, const Vector & end, std::vector<ObjectType> & results) const;
virtual void findOnSegment(Vector const & begin, Vector const & end, SpatialSubdivisionFilter<ObjectType> const & filter, std::vector<ObjectType> & results) const;
virtual void findAtPoint (const Vector & point, std::vector<ObjectType> & results) const;
virtual void findInRange (const Capsule & range, std::vector<ObjectType> & results) const;
virtual void findInRange (const Capsule & range, const SpatialSubdivisionFilter<ObjectType> &filter, std::vector<ObjectType> & results) const;
virtual bool findClosest (const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance) const;
virtual bool findClosest (const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance, int & testCounter) const;
virtual bool findClosest2d (const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance) const;
virtual bool findClosest2d (const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance, int & testCounter) const;
virtual void move (SpatialSubdivisionHandle * object);
virtual void removeObject (SpatialSubdivisionHandle * object);
virtual void validate () const;
virtual int getNodeCount () const;
bool empty () const;
virtual int getObjectCount () const;
void apply (typename SphereTreeNode<ObjectType,ExtentAccessor>::NodeFunctor N);
bool isWithin (Vector const & position) const;
Sphere const & getRealSphere () const;
private:
SphereTree & operator = (const SphereTree & rhs);
SphereTree (const SphereTree & source);
private:
NodeType root;
};
//-----------------------------------------------------------------------
/**
@brief construct a sphere tree
Initializes the root node with no parent.
ExtentAccessor is defined in terms of a struct with a
getExtent(ObjectType) member function that returns a Sphere.
*/
template<class ObjectType, class ExtentAccessor>
inline SphereTree<ObjectType, ExtentAccessor>::SphereTree() :
root()
{
}
//-----------------------------------------------------------------------
/**
@brief destroy the sphere tree
Doesn't do anything. Included here for completeness.
*/
template<class ObjectType, class ExtentAccessor>
inline SphereTree<ObjectType, ExtentAccessor>::~SphereTree()
{
}
//-----------------------------------------------------------------------
/**
@brief add an object to the sphere tree
Calls addObject on the root node.
@see SphereTreeNode
@see SpatialSubdivision::addObject(ObjectType object)
@author Justin Randall
*/
template<class ObjectType, class ExtentAccessor>
inline SpatialSubdivisionHandle * SphereTree<ObjectType, ExtentAccessor>::addObject(ObjectType object)
{
return root.addObject(object);
}
//-----------------------------------------------------------------------
/**
@brief not implemented
@todo implement!
*/
template<class ObjectType, class ExtentAccessor>
inline const bool SphereTree<ObjectType, ExtentAccessor>::canSee(SpatialSubdivisionHandle * target, const Vector & start, const float distance, const float fov) const
{
UNREF(target);
UNREF(start);
UNREF(distance);
UNREF(fov);
//@todo implement
return true;
}
//-----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::dumpSphereTreeObjects(std::vector<ObjectType> & results) const
{
root.dumpSphereTreeObjects(results);
}
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::dumpSphereTree(std::vector<std::pair<ObjectType, Sphere> > & results) const
{
root.dumpSphereTree(results);
}
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::dumpSphereTreeNodes(std::vector<std::pair<ObjectType, Sphere> > & results) const
{
root.dumpSphereTreeNodes(results);
}
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::dumpSphereTreeObjs(std::vector<std::pair<ObjectType, Sphere> > & results) const
{
root.dumpSphereTreeObjs(results);
}
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::dumpEdgeList(std::vector<Vector>& results) const
{
root.dumpEdgeList(results);
}
//-----------------------------------------------------------------------
/**
@brief find all objects contained in a sphere defined by the range params
Finds all objects intersecting the sphere described by the origin and
distance parameters. The results are placed in the results vector.
@param origin A point describing the center of the range query
@param distance The radius of the query. The origin and distance
are used to create a Sphere at 'origin' with radius
'distance'
@param results A user supplied vector of ObjectType that will receive
the solution to the range query.
@see SpatialSubdivision::findInRange()
@see SphereTreeNode::findInRange()
@author Justin Randall
*/
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::findInRange(const Vector & origin, const float distance, std::vector<ObjectType> & results) const
{
const Sphere range(origin, distance);
root.findInRange(range, results);
}
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::findInRange(const Vector & origin, const float distance, std::vector<ObjectType> & results, int & testCounter) const
{
const Sphere range(origin, distance);
root.findInRange(range, results, testCounter);
}
//-----------------------------------------------------------------------
/**
@brief find all objects contained in a sphere defined by the range params
which meet a filter criteria
Finds all objects intersecting the sphere described by the origin and
distance parameters. The results are placed in the results vector.
@param origin A point describing the center of the range query
@param distance The radius of the query. The origin and distance
are used to create a Sphere at 'origin' with radius
'distance'
@param filter A user supplied filter functor.
filter.operator(const ObjectType & object) should return
true if the object is to be returned.
@param results A user supplied vector of ObjectType that will receive
the solution to the range query.
@see SpatialSubdivision::findInRange()
@see SphereTreeNode::findInRange()
@author Acy Stapp
*/
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::findInRange(const Vector & origin, const float distance, const SpatialSubdivisionFilter<ObjectType> &filter, std::vector<ObjectType> & results) const
{
const Sphere range(origin, distance);
root.findInRange(range, filter, results);
}
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::findInRange(const Vector & origin, const float distance, const SpatialSubdivisionFilter<ObjectType> &filter, std::vector<ObjectType> & results, int & testCounter) const
{
const Sphere range(origin, distance);
root.findInRange(range, filter, results, testCounter);
}
//-----------------------------------------------------------------------
/**
@brief find all objects that hit the given ray
Finds all objects intersecting the ray described by the start point
and direction parameters. The results are placed in the results vector.
@param begin A point describing the origin of the ray query
@param dir A vector describing the direction of the ray
@param results A user supplied vector of ObjectType that will receive the results of the query.
@see SpatialSubdivision::findOnRay()
@see SphereTreeNode::findOnRay()
@author Austin Appleby
*/
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::findOnRay(const Vector & begin, const Vector & dir, std::vector<ObjectType> & results) const
{
Vector normDir = dir;
IGNORE_RETURN( normDir.normalize() );
root.findOnRay(begin, normDir, results);
}
//-----------------------------------------------------------------------
/**
@brief find all objects that hit the given segment
Finds all objects intersecting the segment described by the start point
and end point parameters. The results are placed in the results vector.
@param begin The start point of the test segment
@param dir The end point of the test segment
@param results A user supplied vector of ObjectType that will receive the results of the query.
@see SpatialSubdivision::findOnSegment()
@see SphereTreeNode::findOnSegment()
@author Austin Appleby
*/
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::findOnSegment(const Vector & begin, const Vector & end, std::vector<ObjectType> & results) const
{
root.findOnSegment(begin, end, results);
}
//-----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::findOnSegment(Vector const & begin, Vector const & end, SpatialSubdivisionFilter<ObjectType> const & filter, std::vector<ObjectType> & results) const
{
root.findOnSegment(begin, end, filter, results);
}
//-----------------------------------------------------------------------
/**
@brief find all objects that hit the given segment
Finds all objects overlapping the given point.
The results are placed in the results vector.
@param begin The start point of the test segment
@param dir The end point of the test segment
@param results A user supplied vector of ObjectType that will receive the results of the query.
@see SpatialSubdivision::findOnSegment()
@see SphereTreeNode::findOnSegment()
@author Austin Appleby
*/
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::findAtPoint(const Vector & point, std::vector<ObjectType> & results) const
{
root.findAtPoint(point,results);
}
//-----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::findInRange(const Capsule & range, std::vector<ObjectType> & results) const
{
root.findInRange(range, results);
}
//-----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::findInRange(const Capsule & range, const SpatialSubdivisionFilter<ObjectType> &filter, std::vector<ObjectType> & results) const
{
root.findInRange(range, filter, results);
}
//-----------------------------------------------------------------------
/**
@brief Find the closest node in the sphere tree to the given point
Finds the closest object to the given point that is within maxDistance
of it. Returns true if such an object is found.
@param begin The start point
@param maxDistance The maximum distance from the start point we want to search
@param outClosest The closest item found (if one was found)
@param outDistance The distance to the closest item found
@see SphereTreeNode::findClosest()
@author Austin Appleby
*/
template<class ObjectType, class ExtentAccessor>
inline bool SphereTree<ObjectType, ExtentAccessor>::findClosest(const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance ) const
{
outMinDistance = maxDistance;
return root.findClosest(begin, maxDistance, outClosest, outMinDistance, outMaxDistance);
}
template<class ObjectType, class ExtentAccessor>
inline bool SphereTree<ObjectType, ExtentAccessor>::findClosest(const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance, int & testCounter ) const
{
outMinDistance = maxDistance;
return root.findClosest(begin, maxDistance, outClosest, outMinDistance, outMaxDistance, testCounter);
}
//-----------------------------------------------------------------------
/**
@brief Find the closest node in the sphere tree to the given point
Finds the closest (in X-Z) object to the given point that is within maxDistance
of it. Returns true if such an object is found.
@param begin The start point
@param maxDistance The maximum distance (in X-Z) from the start point we want to search
@param outClosest The closest item found (if one was found)
@param outDistance The distance to the closest item found
@see SphereTreeNode::findClosest()
@author Austin Appleby
*/
template<class ObjectType, class ExtentAccessor>
inline bool SphereTree<ObjectType, ExtentAccessor>::findClosest2d(const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance ) const
{
outMinDistance = maxDistance;
return root.findClosest2d(begin, maxDistance, outClosest, outMinDistance, outMaxDistance);
}
template<class ObjectType, class ExtentAccessor>
inline bool SphereTree<ObjectType, ExtentAccessor>::findClosest2d(const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance, int & testCounter ) const
{
outMinDistance = maxDistance;
return root.findClosest2d(begin, maxDistance, outClosest, outMinDistance, outMaxDistance, testCounter);
}
//-----------------------------------------------------------------------
/**
@brief relocate an object in the sphere tree
The sphere tree will find the SphereTreeNode that currently contains
this object. That node is specified in the SpatialSubdivisionHandle
(which is actually a SphereTreeNode::NodeHandle). If the object
remains in the node, the operation completes almost immediately.
If the object leaves it's node, it is re-intergrated in terms of the
parent nodes until a new node is located or created, and he
object handle is updated to reflect the new container node for
the object.
@param object A SphereTreeNode::handle describing the object and the
SphereTreeNode that contains the object
@param start Where the object started moving from
@param end Where the object ends up after moving
@see SpatialSubdivision::move()
@see SphereTreeNode::NodeHandle::move()
@author Justin Randall
*/
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::move(SpatialSubdivisionHandle *object)
{
if (object)
static_cast<typename SphereTreeNode<ObjectType, ExtentAccessor>::NodeHandle *>(object)->move();
}
//-----------------------------------------------------------------------
/**
@brief remove an object from the sphere tree
Advises the containing node that it no longer contains this object.
If the node is empty, then it unlinks itself from the parent node. If
the parent node becomes empty, it unlinks from it's parent. This recurses
until all empty nodes are pruned from the tree.
@param object A SphereTreeNode::NodeHandle pointer describing the
object and the SphereTreeNode that contains the object.
@see SpatialSubdivision::removeObject
@see SphereTreeNode::NodeHandle::removeObject
@author Justin Randall
*/
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::removeObject(SpatialSubdivisionHandle * object)
{
if (object)
static_cast<typename SphereTreeNode<ObjectType, ExtentAccessor>::NodeHandle *>(object)->removeObject();
}
// ----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::validate() const
{
root.validate();
}
// ----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
inline int SphereTree<ObjectType, ExtentAccessor>::getNodeCount() const
{
return root.getNodeCount();
}
// ----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
inline bool SphereTree<ObjectType, ExtentAccessor>::empty() const
{
return root.empty();
}
// ----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
inline int SphereTree<ObjectType, ExtentAccessor>::getObjectCount() const
{
return root.getObjectCount();
}
// ----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::apply(typename SphereTreeNode<ObjectType, ExtentAccessor>::NodeFunctor N)
{
return root.apply(N);
}
//-----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
inline bool SphereTree<ObjectType, ExtentAccessor>::isWithin (Vector const & position) const
{
return root.isWithin (position);
}
// ----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
Sphere const &SphereTree<ObjectType, ExtentAccessor>::getRealSphere() const
{
return root.getRealSphere();
}
// ======================================================================
#endif // _INCLUDED_SphereTree_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,889 @@
// ======================================================================
//
// Transform.cpp
// jeff grills
//
// copyright 1998 Bootprint Entertainment
//
// matrix multiply
//
// a b c d m n o p am+bq+cu an+br+cv ao+bs+cw ap+bt+cx+d
// e f g h q r s t em+fq+gu en+fr+gv eo+fs+gw ep+ft+gx+h
// i j k l * u v w x = im+jq+ku in+jr+kv io+js+kw ip+jt+kx+l
// 0 0 0 1 0 0 0 1 0 0 0 1
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Transform.h"
#include "sharedDebug/DebugFlags.h"
#include "sharedFoundation/ExitChain.h"
#include "sharedMath/Quaternion.h"
#undef TRY_FOR_SSE
#define TRY_FOR_SSE WIN32
#if TRY_FOR_SSE
#include "sharedMath/SseMath.h"
#endif
#include <cfloat>
// ======================================================================
static void xf_matrix_3x4(float *out, const float *left, const float *right);
#if TRY_FOR_SSE
static void sse_xf_matrix_3x4(float *out, const float *left, const float *right);
#endif
// ======================================================================
namespace TransformNamespace
{
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void remove();
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool s_installed;
typedef void (*pf_multiply)(float *out, const float *left, const float *right);
static pf_multiply s_mult_func;
}
using namespace TransformNamespace;
// ======================================================================
const Transform Transform::identity;
// ======================================================================
void TransformNamespace::remove()
{
DEBUG_FATAL(!s_installed, ("Transform not installed."));
s_installed = false;
}
// ======================================================================
void Transform::install()
{
DEBUG_FATAL(s_installed, ("Transform already installed."));
#if TRY_FOR_SSE
if (SseMath::canDoSseMath())
{
s_mult_func = sse_xf_matrix_3x4;
}
else
{
s_mult_func = xf_matrix_3x4;
}
#else
s_mult_func = xf_matrix_3x4;
#endif
s_installed = true;
ExitChain::add(remove, "Transform");
}
// ======================================================================
// Yaw this transform
//
// Remarks:
//
// This routine will rotate the transform around the Y axis by the specified
// number of radians.
//
// Positive rotations are clockwise when viewed looking at the origin from
// the positive side of the axis around which the transform is being rotated.
//
// See Also:
//
// Transform::pitch_l(), Transform::roll_l(),
void Transform::yaw_l(
real radians // Amount to rotate, in radians
)
{
// a b c d C 0 S 0 aC-cS b aS+cC d
// e f g h * 0 1 0 0 = eC-gS f es+gC h
// i j k l -S 0 C 0 iC-kS j iS+kS l
// 0 0 0 1 0 0 0 1 0 0 0 1
const real sine = sin(radians);
const real cosine = cos(radians);
const real a = matrix[0][0];
const real c = matrix[0][2];
const real e = matrix[1][0];
const real g = matrix[1][2];
const real i = matrix[2][0];
const real k = matrix[2][2];
matrix[0][0] = a * cosine + c * -sine;
matrix[0][2] = a * sine + c * cosine;
matrix[1][0] = e * cosine + g * -sine;
matrix[1][2] = e * sine + g * cosine;
matrix[2][0] = i * cosine + k * -sine;
matrix[2][2] = i * sine + k * cosine;
}
// ----------------------------------------------------------------------
/**
* Pitch this transform.
*
* This routine will rotate the transform around the X axis by the specified
* number of radians.
*
* Positive rotations are clockwise when viewed looking at the origin from
* the positive side of the axis around which the transform is being rotated.
*
* @param radians Amount to rotate, in radians
* @see Transform::yaw_l(), Transform::roll_l(),
*/
void Transform::pitch_l(real radians)
{
// a b c d 1 0 0 0 a bC+cS -bS+cC d
// e f g h * 0 C -S 0 = e fC+gS -fS+gC h
// i j k l 0 S C 0 i jC+kS -jS+kC l
// 0 0 0 1 0 0 0 1 0 0 0 1
const real sine = sin(radians);
const real cosine = cos(radians);
const real b = matrix[0][1];
const real c = matrix[0][2];
const real f = matrix[1][1];
const real g = matrix[1][2];
const real j = matrix[2][1];
const real k = matrix[2][2];
matrix[0][1] = b * cosine + c * sine;
matrix[0][2] = b * -sine + c * cosine;
matrix[1][1] = f * cosine + g * sine;
matrix[1][2] = f * -sine + g * cosine;
matrix[2][1] = j * cosine + k * sine;
matrix[2][2] = j * -sine + k * cosine;
}
// ----------------------------------------------------------------------
/**
* Roll this transform.
*
* This routine will rotate the transform around the Z axis by the specified
* number of radians.
*
* Positive rotations are clockwise when viewed looking at the origin from
* the positive side of the axis around which the transform is being rotated.
*
* @param radians Amount to rotate, in radians
* @see Transform::yaw_l(), Transform::pitch_l(),
*/
void Transform::roll_l(real radians)
{
// a b c d C -S 0 0 aC+bS -aS+bC c d
// e f g h * S C 0 0 = eC+fS -eS+fC g h
// i j k l 0 0 1 0 iC+jS -iS+jC k l
// 0 0 0 1 0 0 0 1 0 0 0 1
const real sine = sin(radians);
const real cosine = cos(radians);
const real a = matrix[0][0];
const real b = matrix[0][1];
const real e = matrix[1][0];
const real f = matrix[1][1];
const real i = matrix[2][0];
const real j = matrix[2][1];
matrix[0][0] = a * cosine + b * sine;
matrix[0][1] = a * -sine + b * cosine;
matrix[1][0] = e * cosine + f * sine;
matrix[1][1] = e * -sine + f * cosine;
matrix[2][0] = i * cosine + j * sine;
matrix[2][1] = i * -sine + j * cosine;
}
// ----------------------------------------------------------------------
static void xf_matrix_3x4(float *out, const float *left, const float *right)
{
if (left==out || right==out)
{
float temp[12];
temp[0] = left[0] * right[0] + left[1] * right[4] + left[2] * right[8];
temp[1] = left[0] * right[1] + left[1] * right[5] + left[2] * right[9];
temp[2] = left[0] * right[2] + left[1] * right[6] + left[2] * right[10];
temp[3] = left[0] * right[3] + left[1] * right[7] + left[2] * right[11] + left[3];
temp[4] = left[4] * right[0] + left[5] * right[4] + left[6] * right[8];
temp[5] = left[4] * right[1] + left[5] * right[5] + left[6] * right[9];
temp[6] = left[4] * right[2] + left[5] * right[6] + left[6] * right[10];
temp[7] = left[4] * right[3] + left[5] * right[7] + left[6] * right[11] + left[7];
temp[8] = left[8] * right[0] + left[9] * right[4] + left[10] * right[8];
temp[9] = left[8] * right[1] + left[9] * right[5] + left[10] * right[9];
temp[10]= left[8] * right[2] + left[9] * right[6] + left[10] * right[10];
temp[11]= left[8] * right[3] + left[9] * right[7] + left[10] * right[11] + left[11];
out[0]=temp[0];
out[1]=temp[1];
out[2]=temp[2];
out[3]=temp[3];
out[4]=temp[4];
out[5]=temp[5];
out[6]=temp[6];
out[7]=temp[7];
out[8]=temp[8];
out[9]=temp[9];
out[10]=temp[10];
out[11]=temp[11];
}
else
{
out[0] = left[0] * right[0] + left[1] * right[4] + left[2] * right[8];
out[1] = left[0] * right[1] + left[1] * right[5] + left[2] * right[9];
out[2] = left[0] * right[2] + left[1] * right[6] + left[2] * right[10];
out[3] = left[0] * right[3] + left[1] * right[7] + left[2] * right[11] + left[3];
out[4] = left[4] * right[0] + left[5] * right[4] + left[6] * right[8];
out[5] = left[4] * right[1] + left[5] * right[5] + left[6] * right[9];
out[6] = left[4] * right[2] + left[5] * right[6] + left[6] * right[10];
out[7] = left[4] * right[3] + left[5] * right[7] + left[6] * right[11] + left[7];
out[8] = left[8] * right[0] + left[9] * right[4] + left[10] * right[8];
out[9] = left[8] * right[1] + left[9] * right[5] + left[10] * right[9];
out[10]= left[8] * right[2] + left[9] * right[6] + left[10] * right[10];
out[11]= left[8] * right[3] + left[9] * right[7] + left[10] * right[11] + left[11];
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#if TRY_FOR_SSE
__declspec(naked) void sse_xf_matrix_3x4(float *out, const float *left, const float *right)
{
UNREF(left);
UNREF(right);
UNREF(out);
__asm {
push eax
push ebx
add esp, -48
// [esp + 60] == out
// [esp + 64] == left
// [esp + 68] == right
mov eax, [esp + 64] // left
mov ebx, [esp + 68] // right
movups xmm0, [ebx + 0] // right: row0
movups xmm1, [ebx + 16] // right: row1
movups xmm2, [ebx + 32] // right: row2
// 16-byte align data pointer
lea ebx, [esp+15]
and ebx, -16
///////////////////////////////////////////////////
movaps xmm3, xmm0 // right: row0
movss xmm4, [eax + 0] // left[0][0]
shufps xmm4, xmm4, 0
mulps xmm3, xmm4
movaps xmm5, xmm1 // right: row1
movss xmm6, [eax + 4] // left[0][1]
shufps xmm6, xmm6, 0
mulps xmm5, xmm6
addps xmm5, xmm3
movaps xmm3, xmm2 // right: row2
movss xmm4, [eax + 8] // left[0][2]
shufps xmm4, xmm4, 0
mulps xmm3, xmm4
addps xmm5, xmm3
movss xmm7, [eax + 12] // left[0][3]
shufps xmm7, xmm7, 0x15 //0001 0101
addps xmm5, xmm7
movaps [ebx], xmm5
///////////////////////////////////////////////////
movaps xmm3, xmm0 // right: row0
movss xmm4, [eax + 16] // left[1][0]
shufps xmm4, xmm4, 0
mulps xmm3, xmm4
movaps xmm5, xmm1 // right: row1
movss xmm6, [eax + 20] // left[1][1]
shufps xmm6, xmm6, 0
mulps xmm5, xmm6
addps xmm5, xmm3
movaps xmm3, xmm2 // right: row2
movss xmm4, [eax + 24] // left[1][2]
shufps xmm4, xmm4, 0
mulps xmm3, xmm4
addps xmm5, xmm3
movss xmm7, [eax + 28] // left[1][3]
shufps xmm7, xmm7, 0x15 //0001 0101
addps xmm5, xmm7
movaps [ebx+16], xmm5
///////////////////////////////////////////////////
movaps xmm3, xmm0 // right: row0
movss xmm4, [eax + 32] // left[2][0]
shufps xmm4, xmm4, 0
mulps xmm3, xmm4
movaps xmm5, xmm1 // right: row1
movss xmm6, [eax + 36] // left[2][1]
shufps xmm6, xmm6, 0
mulps xmm5, xmm6
addps xmm5, xmm3
movaps xmm3, xmm2 // right: row2
movss xmm4, [eax + 40] // left[2][2]
shufps xmm4, xmm4, 0
mulps xmm3, xmm4
addps xmm5, xmm3
movss xmm7, [eax + 44] // left[2][3]
shufps xmm7, xmm7, 0x15 //0001 0101
addps xmm5, xmm7
mov eax, [esp+60]
movups [eax+32], xmm5
///////////////////////////////////////////////////
movaps xmm1, [ebx+ 0]
movaps xmm2, [ebx+16]
movups [eax+0 ], xmm1
movups [eax+16], xmm2
mov ebx, [esp + 48]
mov eax, [esp + 52]
add esp, 56
ret
}
}
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------
/**
* Multiply two matrices together.
*
* This routine will properly handle the case where the destination matrix
* is also one or both of the source matrices.
*
* @param lhs Transform on the left-hand side
* @param rhs Transform on the right-hand side
*/
void Transform::multiply(const Transform &lhs, const Transform &rhs)
{
s_mult_func(matrix[0], lhs.matrix[0], rhs.matrix[0]);
}
// ----------------------------------------------------------------------
/**
* Invert a simple transform.
*
* The source matrix has to be composed of purely rotational and translational
* components. It may not contain any scaling or shearing transforms.
*
* @param transform Simple transform to invert
*/
void Transform::invert(const Transform &transform)
{
// transpose the upper 3x3 matrix
matrix[0][0] = transform.matrix[0][0];
matrix[0][1] = transform.matrix[1][0];
matrix[0][2] = transform.matrix[2][0];
matrix[1][0] = transform.matrix[0][1];
matrix[1][1] = transform.matrix[1][1];
matrix[1][2] = transform.matrix[2][1];
matrix[2][0] = transform.matrix[0][2];
matrix[2][1] = transform.matrix[1][2];
matrix[2][2] = transform.matrix[2][2];
// invert the translation
const real x = transform.matrix[0][3];
const real y = transform.matrix[1][3];
const real z = transform.matrix[2][3];
matrix[0][3] = -(matrix[0][0] * x + matrix[0][1] * y + matrix[0][2] * z);
matrix[1][3] = -(matrix[1][0] * x + matrix[1][1] * y + matrix[1][2] * z);
matrix[2][3] = -(matrix[2][0] * x + matrix[2][1] * y + matrix[2][2] * z);
}
// ----------------------------------------------------------------------
/**
* Reorthogonalize a transform.
*
* Repeated rotations will introduce numerical error into the transform,
* which will cause the upper 3x3 matrix to become non-orthonormal. If
* enough error is introduced, weird errors will begin to occur when using
* the transform.
*
* This routine attempts to reduce the numerical error by reorthonormalizing
* the upper 3x3 matrix.
*/
void Transform::reorthonormalize(void)
{
Vector k = getLocalFrameK_p();
Vector j = getLocalFrameJ_p();
if (!k.normalize())
{
DEBUG_FATAL(true, ("could not normalize frame k"));
k = Vector::unitZ; //lint !e527 // Unreachable
}
if (!j.normalize())
{
DEBUG_FATAL(true, ("could not normalize frame j"));
j = Vector::unitY; //lint !e527 // Unreachable
}
// build the remaining vector with the cross product
Vector i = j.cross(k);
// use that result to rebuild the
j = k.cross(i);
// copy the results back into the transform
matrix[0][0] = i.x;
matrix[1][0] = i.y;
matrix[2][0] = i.z;
matrix[0][1] = j.x;
matrix[1][1] = j.y;
matrix[2][1] = j.z;
matrix[0][2] = k.x;
matrix[1][2] = k.y;
matrix[2][2] = k.z;
}
// ----------------------------------------------------------------------
/**
* Send this transform to the DebugPrint system.
*
* The header parameter may be NULL.
*
* @param header Header for the transform
*/
void Transform::debugPrint(const char *header) const
{
if (header)
DEBUG_REPORT_PRINT(true, ("%s\n", header));
for (int i = 0; i < 3; ++i)
DEBUG_REPORT_PRINT(true, (" %-8.2f %-8.2f %-8.2f %-8.2f\n", matrix[i][0], matrix[i][1], matrix[i][2], matrix[i][3]));
}
// ----------------------------------------------------------------------
/**
* Rotate an array of vector from the matrix's current frame to the parent frame.
*
* Pure rotation is most useful for vectors that are orientational, such as
* normals.
*
* The source and result arrays may be the same array.
*
* @param source Source array of vectors to transform
* @param result Array to store the result of the transforms
* @param count Number of vertices to transform
* @see Transform::rotateTranslate_l2p(), Transform::rotate_p2l()
*/
void Transform::rotate_l2p(const Vector *source, Vector *result, int count) const
{
DEBUG_FATAL(!source, ("source array is NULL"));
DEBUG_FATAL(!result, ("result array is NULL"));
DEBUG_FATAL(source == result, ("source and result array can not be the same"));
NOT_NULL(source);
NOT_NULL(result);
for ( ; count; --count, ++source, ++result)
{
const real x = source->x;
const real y = source->y;
const real z = source->z;
result->x = matrix[0][0] * x + matrix[0][1] * y + matrix[0][2] * z;
result->y = matrix[1][0] * x + matrix[1][1] * y + matrix[1][2] * z;
result->z = matrix[2][0] * x + matrix[2][1] * y + matrix[2][2] * z;
}
}
// ----------------------------------------------------------------------
/**
* Transform an array of vectors from the matrix's current frame to the parent frame.
*
* Rotation and translation is most useful for vectors that are position, such as
* vertex data.
*
* The source and result arrays may be the same array.
*
* @param source Source array of vectors to transform
* @param result Array to store the result of the transforms
* @param count Number of vertices to transform
* @see Transform::rotate_l2p(), Transform::rotateTranslate_p2l()
*/
void Transform::rotateTranslate_l2p(const Vector *source, Vector *result, int count) const
{
DEBUG_FATAL(!source, ("source array is NULL"));
DEBUG_FATAL(!result, ("result array is NULL"));
NOT_NULL(source);
NOT_NULL(result);
for ( ; count; --count, ++source, ++result)
{
const real x = source->x;
const real y = source->y;
const real z = source->z;
result->x = matrix[0][0] * x + matrix[0][1] * y + matrix[0][2] * z + matrix[0][3];
result->y = matrix[1][0] * x + matrix[1][1] * y + matrix[1][2] * z + matrix[1][3];
result->z = matrix[2][0] * x + matrix[2][1] * y + matrix[2][2] * z + matrix[2][3];
}
}
// ----------------------------------------------------------------------
/**
* Rotate an array of vectors from the parent's space to the local transform space.
*
* Pure rotation is most useful for vectors that are orientational, such as
* normals.
*
* The source and result arrays may be the same array.
*
* @param source Source array of vectors to transform
* @param result Array to store the result of the transforms
* @param count Number of vertices to transform
* @see Transform::rotateTranslate_p2l(), Transform::rotate_l2p()
*/
void Transform::rotate_p2l(const Vector *source, Vector *result, int count) const
{
DEBUG_FATAL(!source, ("source array is NULL"));
DEBUG_FATAL(!result, ("result array is NULL"));
NOT_NULL(source);
NOT_NULL(result);
for ( ; count; --count, ++source, ++result)
{
const real x = source->x;
const real y = source->y;
const real z = source->z;
result->x = matrix[0][0] * x + matrix[1][0] * y + matrix[2][0] * z;
result->y = matrix[0][1] * x + matrix[1][1] * y + matrix[2][1] * z;
result->z = matrix[0][2] * x + matrix[1][2] * y + matrix[2][2] * z;
}
}
// ----------------------------------------------------------------------
/**
* Transform an array of vectors from the parent spave to the local transform space.
*
* Rotation and translation is most useful for vectors that are position, such as
* vertex data.
*
* The source and result arrays may be the same array.
*
* @param source Source array of vectors to transform
* @param result Array to store the result of the transforms
* @param count Number of vertices to transform
* @see Transform::rotate_p2l(), Transform::rotateTranslate_l2p()
*/
void Transform::rotateTranslate_p2l(const Vector *source, Vector *result, int count) const
{
DEBUG_FATAL(!source, ("source array is NULL"));
DEBUG_FATAL(!result, ("result array is NULL"));
NOT_NULL(source);
NOT_NULL(result);
for ( ; count; --count, ++source, ++result)
{
const real x = source->x - matrix[0][3];
const real y = source->y - matrix[1][3];
const real z = source->z - matrix[2][3];
result->x = matrix[0][0] * x + matrix[1][0] * y + matrix[2][0] * z;
result->y = matrix[0][1] * x + matrix[1][1] * y + matrix[2][1] * z;
result->z = matrix[0][2] * x + matrix[1][2] * y + matrix[2][2] * z;
}
}
// ----------------------------------------------------------------------
const Transform Transform::rotateTranslate_l2p(const Transform &t) const
{
const Vector i = rotate_l2p(t.getLocalFrameI_p());
const Vector j = rotate_l2p(t.getLocalFrameJ_p());
const Vector k = rotate_l2p(t.getLocalFrameK_p());
const Vector p = rotateTranslate_l2p(t.getPosition_p());
Transform tmp;
tmp.setLocalFrameIJK_p(i, j, k);
tmp.setPosition_p(p);
tmp.reorthonormalize();
return tmp;
}
// ----------------------------------------------------------------------
const Transform Transform::rotateTranslate_p2l(const Transform &t) const
{
const Vector i = rotate_p2l(t.getLocalFrameI_p());
const Vector j = rotate_p2l(t.getLocalFrameJ_p());
const Vector k = rotate_p2l(t.getLocalFrameK_p());
const Vector p = rotateTranslate_p2l(t.getPosition_p());
Transform tmp;
tmp.setLocalFrameIJK_p(i, j, k);
tmp.setPosition_p(p);
tmp.reorthonormalize();
return tmp;
}
// ----------------------------------------------------------------------
bool Transform::operator== (const Transform& rhs) const
{
return (memcmp (&rhs, this, sizeof(Transform) ) == 0);
}
// ----------------------------------------------------------------------
bool Transform::operator!= (const Transform& rhs) const
{
return !operator== (rhs);
}
// ----------------------------------------------------------------------
bool Transform::approximates(const Transform &rhs, float rotDelta, float posDelta) const
{
rotDelta = 1-rotDelta;
posDelta *= posDelta;
float dot[3];
int i;
for (i=0; i<3; ++i)
{
dot[i] = matrix[0][i]*rhs.matrix[0][i] + matrix[1][i]*rhs.matrix[1][i] + matrix[2][i]*rhs.matrix[2][i];
}
float dx = matrix[0][3]-rhs.matrix[0][3];
float dy = matrix[1][3]-rhs.matrix[1][3];
float dz = matrix[2][3]-rhs.matrix[2][3];
for (i=0; i<3; ++i)
{
if (dot[i] < rotDelta)
return false;
}
return dx*dx+dy*dy+dz*dz <= posDelta;
}
// ----------------------------------------------------------------------
/**
* Set this Transform to a matrix that does nothing but scale
* objects by the specified amount when computing from local to
* parent space.
*
* @param scale the scale factor applied to x, y, z when transforming from local to parent space.
*/
void Transform::setToScale(const Vector &scaleFactor)
{
matrix[0][0] = scaleFactor.x;
matrix[0][1] = 0.0f;
matrix[0][2] = 0.0f;
matrix[0][3] = 0.0f;
matrix[1][0] = 0.0f;
matrix[1][1] = scaleFactor.y;
matrix[1][2] = 0.0f;
matrix[1][3] = 0.0f;
matrix[2][0] = 0.0f;
matrix[2][1] = 0.0f;
matrix[2][2] = scaleFactor.z;
matrix[2][3] = 0.0f;
}
// ----------------------------------------------------------------------
void Transform::ypr_l(real const y, real const p, real const r)
{
real const cy = cos(y);
real const sy = sin(y);
real const cp = cos(p);
real const sp = sin(p);
real const cr = cos(r);
real const sr = sin(r);
matrix[0][0] = sp * sr * sy + cr * cy;
matrix[0][1] = cr * sp * sy - cy * sr;
matrix[0][2] = cp * sy;
matrix[1][0] = cp * sr;
matrix[1][1] = cp * cr;
matrix[1][2] = -sp;
matrix[2][0] = cy * sp * sr - cr * sy;
matrix[2][1] = cr * cy * sp + sr * sy;
matrix[2][2] = cp * cy;
}
// ----------------------------------------------------------------------
namespace
{
class ValidateBad
{
public:
ValidateBad();
~ValidateBad();
void checked();
private:
int m_checked;
};
}
ValidateBad::ValidateBad()
: m_checked(0)
{
}
ValidateBad::~ValidateBad()
{
REPORT_LOG(m_checked != 0, ("%d transforms checked", m_checked));
}
void ValidateBad::checked()
{
++m_checked;
}
static float magnitudeThreshold = 0.0001f;
static float dotThreshold = cos(convertDegreesToRadians(0.05f));
static bool validate(bool allowFail, Vector const & a, Vector const & b)
{
const float magnitude = a.magnitude();
if (!WithinEpsilonInclusive(1.0f, magnitude, magnitudeThreshold))
{
FATAL(!allowFail, ("Transform magnitude %0.12f", magnitude));
return false;
}
Vector a2 = a;
IGNORE_RETURN( a2.normalize() );
const float dot = a2.dot(b);
if (dot < dotThreshold)
{
FATAL(!allowFail, ("Transform angle off %0.12f", dot));
return false;
}
return true;
}
bool Transform::isNaN() const
{
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 4; ++j)
{
#ifdef WIN32
if(_isnan( static_cast<double>(matrix[i][j])))
{
DEBUG_FATAL(true, ("nan"));
return true;
}
#else
if(isnan(matrix[i][j]))
{
DEBUG_FATAL(true, ("nan"));
return true;
}
#endif
}
}
return false;
}
bool Transform::realValidate(bool allowFail) const
{
static ValidateBad vb;
vb.checked();
IGNORE_RETURN(isNaN());
Transform t = *this;
t.reorthonormalize();
t.reorthonormalize();
t.reorthonormalize();
if (!::validate(allowFail, getLocalFrameI_p(), t.getLocalFrameI_p()))
return false;
if (!::validate(allowFail, getLocalFrameJ_p(), t.getLocalFrameJ_p()))
return false;
if (!::validate(allowFail, getLocalFrameK_p(), t.getLocalFrameK_p()))
return false;
Quaternion q(*this);
Transform u(IF_none);
q.getTransform(&u);
if (!::validate(allowFail, u.getLocalFrameI_p(), t.getLocalFrameI_p()))
return false;
if (!::validate(allowFail, u.getLocalFrameJ_p(), t.getLocalFrameJ_p()))
return false;
if (!::validate(allowFail, u.getLocalFrameK_p(), t.getLocalFrameK_p()))
return false;
return true;
}
// ======================================================================
@@ -0,0 +1,615 @@
// ======================================================================
//
// Transform.h
// Portions copyright 1998 Bootprint Entertainment
// Portions copyright 2000-2001 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_Transform_H
#define INCLUDED_Transform_H
// ======================================================================
#include "sharedMath/Vector.h"
// ======================================================================
namespace DPVS
{
class Matrix4x4;
}
class Transform
{
friend class Direct3d8;
friend class Direct3d9;
friend class Iff;
friend class MayaUtility;
friend class OpenGL;
friend class Quaternion;
friend class SseMath;
friend class RenderWorld;
public:
enum InitializeFlag
{
IF_none
};
public:
static const Transform identity;
public:
static void install();
public:
typedef real matrix_t[3][4];
Transform(void);
explicit Transform(InitializeFlag noInitialization);
void debugPrint(const char *header) const;
void reorthonormalize(void);
void DLLEXPORT multiply(const Transform &lhs, const Transform &rhs);
void invert(const Transform &transform);
void move_l(const Vector &vec);
void move_p(const Vector &vec);
void yaw_l(real radians);
void pitch_l(real radians);
void roll_l(real radians);
// set ypr of the matrix.
void ypr_l(real y, real p, real r);
void ypr_l(Vector const & ypr);
void resetRotate_l2p(void);
void resetRotateTranslate_l2p(void);
const Vector getPosition_p(void) const;
void setPosition_p(const Vector &vec);
void setPosition_p(real x, real y, real z);
const Vector getLocalFrameI_p(void) const;
const Vector getLocalFrameJ_p(void) const;
const Vector getLocalFrameK_p(void) const;
void setLocalFrameIJK_p(const Vector &i, const Vector &j, const Vector &k);
void setLocalFrameKJ_p(const Vector &k, const Vector &j);
const Vector getParentFrameI_l(void) const;
const Vector getParentFrameJ_l(void) const;
const Vector getParentFrameK_l(void) const;
const Vector rotate_l2p(const Vector &vec) const;
const Vector rotateTranslate_l2p(const Vector &vec) const;
const Vector rotate_p2l(const Vector &vec) const;
const Vector rotateTranslate_p2l(const Vector &vec) const;
const Transform rotateTranslate_l2p(const Transform &t) const;
const Transform rotateTranslate_p2l(const Transform &t) const;
void rotate_l2p(const Vector *source, Vector *result, int count) const;
void rotateTranslate_l2p(const Vector *source, Vector *result, int count) const;
void rotate_p2l(const Vector *source, Vector *result, int count) const;
void rotateTranslate_p2l(const Vector *source, Vector *result, int count) const;
bool operator== (const Transform& rhs) const;
bool operator!= (const Transform& rhs) const;
bool approximates(const Transform &rhs, float rotDelta=0.001f, float posEpsilon=0.001f) const;
bool validate(bool allowFail=false) const;
bool isNaN() const;
bool isYawOnly(void) const;
bool isTranslateOnly(void) const;
void setToScale(const Vector &scaleFactor);
void scale(float uniformScaleFactor);
void scalePosition_p(float uniformScaleFactor);
const matrix_t &getMatrix() const { return matrix; }
private:
bool realValidate(bool allowFail) const;
private:
matrix_t matrix;
};
// ======================================================================
// Turn this Transform into the identity transform
//
// Remarks:
//
// The identity Transform consists of a matrix of all 0 values with the exception of
// the diagonal, which is all 1 values. This matrix will result in no change when
// multiplied against other matrices or transforming vectors.
inline void Transform::resetRotateTranslate_l2p(void)
{
// make the diagonal 1's to form the identity matrix
matrix[0][0] = CONST_REAL(1);
matrix[0][1] = CONST_REAL(0);
matrix[0][2] = CONST_REAL(0);
matrix[0][3] = CONST_REAL(0);
matrix[1][0] = CONST_REAL(0);
matrix[1][1] = CONST_REAL(1);
matrix[1][2] = CONST_REAL(0);
matrix[1][3] = CONST_REAL(0);
matrix[2][0] = CONST_REAL(0);
matrix[2][1] = CONST_REAL(0);
matrix[2][2] = CONST_REAL(1);
matrix[2][3] = CONST_REAL(0);
}
// ----------------------------------------------------------------------
/**
* Set the orientation to the identity orientation.
*
* This routine does NOT affect position
*/
inline void Transform::resetRotate_l2p(void)
{
matrix[0][0] = CONST_REAL(1);
matrix[0][1] = CONST_REAL(0);
matrix[0][2] = CONST_REAL(0);
matrix[1][0] = CONST_REAL(0);
matrix[1][1] = CONST_REAL(1);
matrix[1][2] = CONST_REAL(0);
matrix[2][0] = CONST_REAL(0);
matrix[2][1] = CONST_REAL(0);
matrix[2][2] = CONST_REAL(1);
}
// ----------------------------------------------------------------------
/**
* Construct a Transform.
*
* The transform will be initialized to the identity matrix.
*
* @see Transform::makeIdentity()
*/
inline Transform::Transform(void)
{
resetRotateTranslate_l2p();
}
// ----------------------------------------------------------------------
/**
* Construct a Transform without initialization.
*
* The transform matrix will not be initialized. This
* member is intended for use only when efficiency is
* a premium.
*
* @see Transform::Transform()
*/
inline Transform::Transform(InitializeFlag noInitialization)
{
UNREF(noInitialization);
} //lint !e1401 // warning, member 'matrix' not initialized // that's right, caller beware
// ----------------------------------------------------------------------
/**
* Move the transform in it's parent space.
*
* This routine moves the transform in it's parent space, or the world space if
* the transform has no parent. Therefore, moving along the Z axis will move the
* transform forward along the Z-axis of it's parent space, not forward in the
* direction in which it is pointed.
*
* @param vec Displacement to move in parent space
* @see Transform::move_l()
*/
inline void Transform::move_p(const Vector &vec)
{
matrix[0][3] += vec.x;
matrix[1][3] += vec.y;
matrix[2][3] += vec.z;
}
// ----------------------------------------------------------------------
/**
* Get the positional offset of this transform.
*
* This routine returns a temporary.
*
* The position returned is in parent space, which is world space if the
* Transform has no parent.
*
* @return The positional offest of this transform in parent space.
*/
inline const Vector Transform::getPosition_p(void) const
{
return Vector(matrix[0][3], matrix[1][3], matrix[2][3]);
}
// ----------------------------------------------------------------------
/**
* Set the positional offset of this transform.
*
* The position is specified in parent space, which is world space if the
* Transform has no parent.
*
* @param vec New translation for this transform
*/
inline void Transform::setPosition_p(const Vector &vec)
{
matrix[0][3] = vec.x;
matrix[1][3] = vec.y;
matrix[2][3] = vec.z;
}
// ----------------------------------------------------------------------
/**
* Set the positional offset of this transform.
*
* The position is specified in parent space, which is world space if the
* Transform has no parent.
*
* @param x New X translation for this transform
* @param y New Y translation for this transform
* @param z New Z translation for this transform
*/
inline void Transform::setPosition_p(real x, real y, real z)
{
matrix[0][3] = x;
matrix[1][3] = y;
matrix[2][3] = z;
}
// ----------------------------------------------------------------------
/**
* Set the transform matrix from the I, J, and K vectors.
*
* This routine assumes that I, J, and K are a left-handed orthonormal basis.
* If they are not, the reorthonormalize() routine must be called after this routine.
*
* @param i Unit vector along the X axis
* @param j Unit vector along the Y axis
* @param k Unit vector along the Z axis
*/
inline void Transform::setLocalFrameIJK_p(const Vector &i, const Vector &j, const Vector &k)
{
matrix[0][0] = i.x;
matrix[1][0] = i.y;
matrix[2][0] = i.z;
matrix[0][1] = j.x;
matrix[1][1] = j.y;
matrix[2][1] = j.z;
matrix[0][2] = k.x;
matrix[1][2] = k.y;
matrix[2][2] = k.z;
}
// ----------------------------------------------------------------------
/**
* Set the transform matrix from K and J vectors.
*
* This routine assumes that K and J are part of a left-handed orthonormal basis.
* If they are not, the reorthonormalize() routine must be called after this routine.
*
* @param k Unit vector along the Z axis
* @param j Unit vector along the Y axis
*/
inline void Transform::setLocalFrameKJ_p(const Vector &k, const Vector &j)
{
Vector i = j.cross(k);
setLocalFrameIJK_p(i, j, k);
}
// ----------------------------------------------------------------------
/**
* Get the parent-space vector pointing along the X axis of this frame of reference.
*
* This routine returns a temporary.
*
* The vector returned is in parent space, which is world space if the
* Transform has no parent.
*
* @return The vector pointing along the X axis of the frame in parent space
*/
inline const Vector Transform::getLocalFrameI_p(void) const
{
return Vector(matrix[0][0], matrix[1][0], matrix[2][0]);
}
// ----------------------------------------------------------------------
/**
* Get the parent-space vector pointing along the Y axis of this frame of reference.
*
* This routine returns a temporary.
*
* The vector returned is in parent space, which is world space if the
* Transform has no parent.
*
* @return The vector pointing along the Y axis of the frame in parent space
*/
inline const Vector Transform::getLocalFrameJ_p(void) const
{
return Vector(matrix[0][1], matrix[1][1], matrix[2][1]);
}
// ----------------------------------------------------------------------
/**
* Get the parent-space vector pointing along the Z axis of this frame of reference.
*
* This routine returns a temporary.
*
* The position returned is in parent space, which is world space if the
* Transform has no parent.
*
* @return The vector pointing along the Z axis of the frame in parent space
*/
inline const Vector Transform::getLocalFrameK_p(void) const
{
return Vector(matrix[0][2], matrix[1][2], matrix[2][2]);
}
// ----------------------------------------------------------------------
/**
* Get the transform-space vector pointing along the X axis of the parent of reference.
*
* This routine returns a temporary.
*
* The vector returned is in local space.
*
* @return The vector pointing along the X axis of the parent's frame in local space
*/
inline const Vector Transform::getParentFrameI_l(void) const
{
return Vector(matrix[0][0], matrix[0][1], matrix[0][2]);
}
// ----------------------------------------------------------------------
/**
* Get the transform-space vector pointing along the Y axis of the parent of reference.
*
* This routine returns a temporary.
*
* The vector returned is in local space.
*
* @return The vector pointing along the Y axis of the parent's frame in local space
*/
inline const Vector Transform::getParentFrameJ_l(void) const
{
return Vector(matrix[1][0], matrix[1][1], matrix[1][2]);
}
// ----------------------------------------------------------------------
/**
* Get the transform-space vector pointing along the Z axis of the parent of reference.
*
* This routine returns a temporary.
*
* The vector returned is in local space.
*
* @return The vector pointing along the Z axis of the parent's frame in local space
*/
inline const Vector Transform::getParentFrameK_l(void) const
{
return Vector(matrix[2][0], matrix[2][1], matrix[2][2]);
}
// ----------------------------------------------------------------------
/**
* Rotate vector from the matrix's current frame to the parent frame.
*
* This routine returns a temporary.
*
* Pure rotation is most useful for vectors that are orientational, such as
* normals.
*
* @param vec Vector to rotate
* @return The vector in parent space
* @see Transform::rotateTranslate_l2p(), Transform::rotate_p2l()
*/
inline const Vector Transform::rotate_l2p(const Vector &vec) const
{
return Vector(
matrix[0][0] * vec.x + matrix[0][1] * vec.y + matrix[0][2] * vec.z,
matrix[1][0] * vec.x + matrix[1][1] * vec.y + matrix[1][2] * vec.z,
matrix[2][0] * vec.x + matrix[2][1] * vec.y + matrix[2][2] * vec.z);
}
// ----------------------------------------------------------------------
/**
* Transform the vector from the matrix's current frame to the parent frame.
*
* This routine returns a temporary.
*
* Rotation and translation is most useful for vectors that are position, such as
* vertex data.
*
* @param vec Vector to rotate and translate
* @return The vector in parent space
* @see Transform::rotate_l2p(), Transform::rotateTranslate_p2l()
*/
inline const Vector Transform::rotateTranslate_l2p(const Vector &vec) const
{
return Vector (
matrix[0][0] * vec.x + matrix[0][1] * vec.y + matrix[0][2] * vec.z + matrix[0][3],
matrix[1][0] * vec.x + matrix[1][1] * vec.y + matrix[1][2] * vec.z + matrix[1][3],
matrix[2][0] * vec.x + matrix[2][1] * vec.y + matrix[2][2] * vec.z + matrix[2][3]);
}
// ----------------------------------------------------------------------
/**
* Rotate vector from the parent's space to the local transform space.
*
* This routine returns a temporary.
*
* Pure rotation is most useful for vectors that are orientational, such as
* normals.
*
* @param vec Vector to rotate
* @return The vector in local space
* @see Transform::rotateTranslate_p2l(), Transform::rotate_l2p()
*/
inline const Vector Transform::rotate_p2l(const Vector &vec) const
{
return Vector (
matrix[0][0] * vec.x + matrix[1][0] * vec.y + matrix[2][0] * vec.z,
matrix[0][1] * vec.x + matrix[1][1] * vec.y + matrix[2][1] * vec.z,
matrix[0][2] * vec.x + matrix[1][2] * vec.y + matrix[2][2] * vec.z);
}
// ----------------------------------------------------------------------
/**
* Transform the vector from the parent spave to the local transform space.
*
* This routine returns a temporary.
*
* Rotation and translation is most useful for vectors that are position, such as
* vertex data.
*
* @return The vector in local space
* @see Transform::rotate_p2l(), Transform::rotateTranslate_l2p()
*/
inline const Vector Transform::rotateTranslate_p2l(const Vector &vec) const
{
const real x = vec.x - matrix[0][3];
const real y = vec.y - matrix[1][3];
const real z = vec.z - matrix[2][3];
return Vector(
matrix[0][0] * x + matrix[1][0] * y + matrix[2][0] * z,
matrix[0][1] * x + matrix[1][1] * y + matrix[2][1] * z,
matrix[0][2] * x + matrix[1][2] * y + matrix[2][2] * z);
}
// ----------------------------------------------------------------------
/**
* Move the transform in it's own local space.
*
* This routine moves the transform according to its current frame of reference.
* Therefore, moving along the Z axis will move the transform forward in the direction
* in which it is pointed.
*
* @param vec Vector to rotate and translate
* @see Transform::moveInParentSpace()
*/
inline void Transform::move_l(const Vector &vec)
{
move_p(rotate_l2p(vec));
}
// ----------------------------------------------------------------------
// Returns true if the rotation component of a transform is yaw-only
// (no X- or Z-axis rotation)
// This test is very simple when we're guaranteed that our axes are orthonormal
inline bool Transform::isYawOnly(void) const
{
return abs(matrix[1][1] - 1.0f) < 0.00001f;
}
// ----------------------------------------------------------------------
// Returns true if the transform does no rotation.
// This test is very simple when we're guaranteed that our axes are orthonormal
inline bool Transform::isTranslateOnly(void) const
{
if(abs(matrix[0][0] - 1.0f) > 0.00001f) return false;
if(abs(matrix[1][1] - 1.0f) > 0.00001f) return false;
if(abs(matrix[2][2] - 1.0f) > 0.00001f) return false;
return true;
}
// ----------------------------------------------------------------------
inline bool Transform::validate(bool allowFail) const
{
UNREF(allowFail);
// return realValidate(allowFail);
return true;
}
// ----------------------------------------------------------------------
/**
* Set the uniform scale factor applied to the transform's rotation
* matrix.
*
* This function does not manipulate the position information within
* the parent space.
*
* @param uniformScaleFactor the scale factor to apply to the diagonal
* of the rotation matrix.
*
* @see Transform::scalePosition_p().
*/
inline void Transform::scale(float uniformScaleFactor)
{
matrix[0][0] *= uniformScaleFactor;
matrix[1][1] *= uniformScaleFactor;
matrix[2][2] *= uniformScaleFactor;
}
// ----------------------------------------------------------------------
/**
* Scale the parent-space positioning information for the Transform.
*
* @param uniformScaleFactor the scale factor to apply to the position
* of the Transform in parent space.
*/
inline void Transform::scalePosition_p(float uniformScaleFactor)
{
matrix[0][3] *= uniformScaleFactor;
matrix[1][3] *= uniformScaleFactor;
matrix[2][3] *= uniformScaleFactor;
}
// ----------------------------------------------------------------------
inline void Transform::ypr_l(Vector const & ypr)
{
ypr_l(ypr.x, ypr.y, ypr.z);
}
// ======================================================================
#endif
@@ -0,0 +1,118 @@
//===================================================================
//
// Transform2d.cpp
// asommers
//
// copyright 2002, sony online entertainment
//
//===================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Transform2d.h"
#include "sharedMath/Rectangle2d.h"
//===================================================================
const Transform2d Transform2d::identity;
//===================================================================
//-------------------------------------------------------------------
void Transform2d::yaw_l (float radians)
{
const float sine = sin (radians);
const float cosine = cos (radians);
const float a = m_matrix [0][0];
const float b = m_matrix [0][1];
const float c = m_matrix [1][0];
const float d = m_matrix [1][1];
m_matrix [0][0] = a * cosine + b * -sine;
m_matrix [0][1] = a * sine + b * cosine;
m_matrix [1][0] = c * cosine + d * -sine;
m_matrix [1][1] = c * sine + d * cosine;
}
//-------------------------------------------------------------------
void Transform2d::rotateTranslate_p2l(Rectangle2d &o_result, const Rectangle2d &r) const
{
const float x0 = r.x0 - m_matrix[0][2];
const float y0 = r.y0 - m_matrix[1][2];
const float x1 = r.x1 - m_matrix[0][2];
const float y1 = r.y1 - m_matrix[1][2];
float tx0, tx1, ty0, ty1;
//-------------------------
// calculate max and min x
tx0=m_matrix[0][0]*x0;
tx1=m_matrix[0][0]*x1;
ty0=m_matrix[1][0]*y0;
ty1=m_matrix[1][0]*y1;
if (tx1>=tx0)
{
if (ty1>=ty0)
{
o_result.x1=tx1+ty1;
o_result.x0=tx0+ty0;
}
else
{
o_result.x1=tx1+ty0;
o_result.x0=tx0+ty1;
}
}
else
{
if (ty1>=ty0)
{
o_result.x1=tx0+ty1;
o_result.x0=tx1+ty0;
}
else
{
o_result.x1=tx0+ty0;
o_result.x0=tx1+ty1;
}
}
//-------------------------
//-------------------------
// calculate max and min y
tx0=m_matrix[0][1]*x0;
tx1=m_matrix[0][1]*x1;
ty0=m_matrix[1][1]*y0;
ty1=m_matrix[1][1]*y1;
if (tx1>=tx0)
{
if (ty1>=ty0)
{
o_result.y1=tx1+ty1;
o_result.y0=tx0+ty0;
}
else
{
o_result.y1=tx1+ty0;
o_result.y0=tx0+ty1;
}
}
else
{
if (ty1>=ty0)
{
o_result.y1=tx0+ty1;
o_result.y0=tx1+ty0;
}
else
{
o_result.y1=tx0+ty0;
o_result.y0=tx1+ty1;
}
}
//-------------------------
}
//-------------------------------------------------------------------
@@ -0,0 +1,171 @@
//===================================================================
//
// Transform2d.h
// asommers
//
// copyright 2002, sony online entertainment
//
//===================================================================
#ifndef INCLUDED_Transform2d_H
#define INCLUDED_Transform2d_H
//===================================================================
#include "sharedMath/Vector2d.h"
//===================================================================
class Rectangle2d;
//===================================================================
class Transform2d
{
public:
static const Transform2d identity;
public:
Transform2d ();
void move_l (const Vector2d& v);
void move_p (const Vector2d& v);
void yaw_l (float radians);
void resetRotate_l2p ();
void resetRotateTranslate_l2p ();
const Vector2d getPosition_p () const;
void setPosition_p (const Vector2d& v);
void setPosition_p (float x, float y);
const Vector2d rotate_l2p (const Vector2d& v) const;
const Vector2d rotateTranslate_l2p (const Vector2d& v) const;
const Vector2d rotate_p2l (const Vector2d& v) const;
const Vector2d rotateTranslate_p2l (const Vector2d& v) const;
//----------------------------------------------------------------------------
// Returns the result equivalent to expanding the source rectangle into its
// four corner points, transform each four points using rotateTranslate_p2l,
// and then finding the resulting bounding rectangle of those four points.
// 'r' and 'o_result' may reference the same object.
void rotateTranslate_p2l(Rectangle2d &o_result, const Rectangle2d &r) const;
//----------------------------------------------------------------------------
bool operator== (const Transform2d& rhs) const;
bool operator!= (const Transform2d& rhs) const;
private:
float m_matrix [2][3];
};
//-------------------------------------------------------------------
inline void Transform2d::resetRotateTranslate_l2p ()
{
// make the diagonal 1's to form the identity m_matrix
m_matrix [0][0] = 1.f;
m_matrix [0][1] = 0.f;
m_matrix [0][2] = 0.f;
m_matrix [1][0] = 0.f;
m_matrix [1][1] = 1.f;
m_matrix [1][2] = 0.f;
}
//-------------------------------------------------------------------
inline void Transform2d::resetRotate_l2p ()
{
m_matrix [0][0] = 1.f;
m_matrix [0][1] = 0.f;
m_matrix [1][0] = 0.f;
m_matrix [1][1] = 1.f;
}
//-------------------------------------------------------------------
inline Transform2d::Transform2d ()
{
resetRotateTranslate_l2p ();
}
//-------------------------------------------------------------------
inline void Transform2d::move_p (const Vector2d& v)
{
m_matrix [0][2] += v.x;
m_matrix [1][2] += v.y;
}
//-------------------------------------------------------------------
inline void Transform2d::move_l (const Vector2d& v)
{
move_p (rotate_l2p (v));
}
//-------------------------------------------------------------------
inline const Vector2d Transform2d::getPosition_p () const
{
return Vector2d (m_matrix [0][2], m_matrix [1][2]);
}
//-------------------------------------------------------------------
inline void Transform2d::setPosition_p (const Vector2d& v)
{
m_matrix [0][2] = v.x;
m_matrix [1][2] = v.y;
}
//-------------------------------------------------------------------
inline void Transform2d::setPosition_p (float x, float y)
{
m_matrix [0][2] = x;
m_matrix [1][2] = y;
}
//-------------------------------------------------------------------
inline const Vector2d Transform2d::rotate_l2p (const Vector2d& v) const
{
return Vector2d (m_matrix [0][0] * v.x + m_matrix [0][1] * v.y, m_matrix [1][0] * v.x + m_matrix [1][1] * v.y);
}
//-------------------------------------------------------------------
inline const Vector2d Transform2d::rotateTranslate_l2p (const Vector2d& v) const
{
return Vector2d (m_matrix [0][0] * v.x + m_matrix [0][1] * v.y + m_matrix [0][2], m_matrix [1][0] * v.x + m_matrix [1][1] * v.y + m_matrix [1][2]);
}
//-------------------------------------------------------------------
inline const Vector2d Transform2d::rotate_p2l (const Vector2d& v) const
{
return Vector2d (m_matrix [0][0] * v.x + m_matrix [1][0] * v.y, m_matrix [0][1] * v.x + m_matrix [1][1] * v.y);
}
//-------------------------------------------------------------------
inline const Vector2d Transform2d::rotateTranslate_p2l (const Vector2d& v) const
{
const float x = v.x - m_matrix[0][2];
const float y = v.y - m_matrix[1][2];
return Vector2d(
m_matrix[0][0]*x + m_matrix[1][0]*y,
m_matrix[0][1]*x + m_matrix[1][1]*y
);
}
//===================================================================
#endif
@@ -0,0 +1,321 @@
// ======================================================================
//
// Vector.cpp
// Portions copyright 1998 Bootprint Entertainment.
// Portions copyright 2000-2001 Sony Online Entertainment.
// All Rights Reserved.
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Vector.h"
#include "sharedRandom/Random.h"
#include <vector>
// ======================================================================
const Vector Vector::unitX(CONST_REAL(1), CONST_REAL(0), CONST_REAL(0));
const Vector Vector::unitY(CONST_REAL(0), CONST_REAL(1), CONST_REAL(0));
const Vector Vector::unitZ(CONST_REAL(0), CONST_REAL(0), CONST_REAL(1));
const Vector Vector::negativeUnitX(CONST_REAL(-1), CONST_REAL( 0), CONST_REAL( 0));
const Vector Vector::negativeUnitY(CONST_REAL( 0), CONST_REAL(-1), CONST_REAL( 0));
const Vector Vector::negativeUnitZ(CONST_REAL( 0), CONST_REAL( 0), CONST_REAL(-1));
const Vector Vector::zero(CONST_REAL(0), CONST_REAL(0), CONST_REAL(0));
const Vector Vector::xyz111(CONST_REAL(1), CONST_REAL(1), CONST_REAL(1));
const Vector Vector::maxXYZ(REAL_MAX, REAL_MAX, REAL_MAX);
const Vector Vector::negativeMaxXYZ(-REAL_MAX, -REAL_MAX, -REAL_MAX);
const real Vector::NORMALIZE_THRESHOLD(CONST_REAL(0.00001));
const real Vector::NORMALIZED_EPSILON(CONST_REAL(0.00001));
// If M is between 1-e and 1+e, then M^2 is between 1-2e+e^2 and 1+2e+e^2.
static const real NORMALIZED_RANGE_SQUARED_MIN = (1.0f - (2.0f * Vector::NORMALIZED_EPSILON)) + (Vector::NORMALIZED_EPSILON * Vector::NORMALIZED_EPSILON);
static const real NORMALIZED_RANGE_SQUARED_MAX = (1.0f + (2.0f * Vector::NORMALIZED_EPSILON)) + (Vector::NORMALIZED_EPSILON * Vector::NORMALIZED_EPSILON);
// ======================================================================
// Normalize a vector to a length of 1
//
// Return value:
//
// True if the vector has been normalized, otherwise false.
//
// Remarks:
//
// If the vector is too small, it cannot be normalized.
bool Vector::normalize(void)
{
real mag = magnitude();
if (mag < NORMALIZE_THRESHOLD)
return false;
*this /= mag;
return true;
}
// ----------------------------------------------------------------------
/**
* Normalize a vector to a length of approximately 1.
*
* If the vector is too small, it cannot be normalized.
*
* @return True if the vector has been approximately normalized, otherwise false.
*/
bool Vector::approximateNormalize(void)
{
real mag = approximateMagnitude();
if (mag < NORMALIZE_THRESHOLD)
return false;
*this /= mag;
return true;
}
// ----------------------------------------------------------------------
/**
* Return true if a vector is of length 1 (within some tolerance)
*
* Vectors normalized with Vector::normalize() should always be of unit
* length within tolerance, vectors normalized with Vector::approximate
* Normalize will not.
*
* @return True if the vector's length is within NORMALIZED_TOLERANCE of 1
*/
bool Vector::isNormalized(void) const
{
real mag2 = magnitudeSquared();
return WithinRangeInclusiveInclusive(NORMALIZED_RANGE_SQUARED_MIN,mag2,NORMALIZED_RANGE_SQUARED_MAX);
}
// ----------------------------------------------------------------------
/**
* Find the point on the specified line that is as close to this point as possible.
*
* The line is treated as an infinite line, not a line segment.
*
* @param line0 First point on the line
* @param line1 Second point on the line
* @param t Parameteric time along the line that is closest to this vector
*/
const Vector Vector::findClosestPointOnLine(const Vector &line0, const Vector &line1, real *t) const
{
DEBUG_FATAL(!t, ("t arg is null"));
NOT_NULL(t);
Vector delta(line1 - line0);
const real r = (*this - line0).dot(delta) / delta.magnitudeSquared();
*t = r;
return line0 + delta * r;
}
// ----------------------------------------------------------------------
/**
* Find the point on the specified line that is as close to this point as possible.
*
* The line is treated as an infinite line, not a line segment.
*
* @param line0 First point on the line
* @param line1 Second point on the line
*/
const Vector Vector::findClosestPointOnLine(const Vector &line0, const Vector &line1) const
{
real t;
return findClosestPointOnLine(line0, line1, &t);
}
//-----------------------------------------------------------------------
const Vector Vector::findClosestPointOnLineSegment(const Vector & startPoint, const Vector & endPoint) const
{
Vector delta(endPoint - startPoint);
// if these vectors describe a point instead of a line-segment, return the startpoint
// rather than returning an invalid vector
const real deltaMagnitudeSquared = delta.magnitudeSquared();
if(deltaMagnitudeSquared <NORMALIZE_THRESHOLD)
return startPoint;
const real r = clamp(CONST_REAL(0), (*this - startPoint).dot(delta) / deltaMagnitudeSquared, CONST_REAL(1));
return startPoint + delta * r;
}
// ----------------------------------------------------------------------
/**
* Calculate the distance from this point to the specified line.
*
* The line is treated as an infinite line, not a line segment.
*
* @param line0 First point on the line
* @param line1 Second point on the line
*/
real Vector::distanceToLine(const Vector &line0, const Vector &line1) const
{
return magnitudeBetween(findClosestPointOnLine(line0, line1));
}
// ----------------------------------------------------------------------
/**
* Calculate the distance from this point to the specified line segment.
*
* @param line0 First point on the line
* @param line1 Second point on the line
*/
real Vector::distanceToLineSegment(const Vector &line0, const Vector &line1) const
{
return magnitudeBetween(findClosestPointOnLineSegment(line0, line1));
}
// ----------------------------------------------------------------------
/**
* Send this vector to the DebugPrint system.
*
* The header parameter may be NULL.
*
* @param header Header for the vector
*/
void Vector::debugPrint(const char *header) const
{
if (header)
DEBUG_REPORT_PRINT(true, ("%s: ", header));
DEBUG_REPORT_PRINT(true, (" %-8.2f %-8.2f %-8.2f\n", x, y, z));
}
// ----------------------------------------------------------------------
/**
* Create a random unit vector.
*
* This routine will return an evenly distributed random vector on the
* unit sphere.
*/
const Vector Vector::randomUnit(void)
{
// from the comp.graphics.algorithm FAQ
const real lz = cos(Random::randomReal(0.0f, PI));
const real t = Random::randomReal(0.f, PI_TIMES_2);
const real r = sqrt(1.0f - sqr(lz));
return Vector(r * cos(t), r * sin(t), lz);
}
// ----------------------------------------------------------------------
/**
* Create a random vector.
*
* The vector will be within the cube [ -halfSideLength .. halfSideLength ].
*
* @param halfSideLength Size of the cube
*/
const Vector Vector::randomCube(real halfSideLength)
{
return Vector(Random::randomReal(-halfSideLength, halfSideLength), Random::randomReal(-halfSideLength, halfSideLength), Random::randomReal(-halfSideLength, halfSideLength));
}
// ----------------------------------------------------------------------
/**
* Test whether a point lies within a triangle.
*
* This should be on at least the plane for the test to work. See Plane::findIntersection ()
*/
namespace {
// adapated from http://www.blackpawn.com/texts/pointinpoly/default.html
inline bool sameSide(const Vector &p1, const Vector &p2, const Vector &a, const Vector &b)
{
Vector const ba(b - a);
Vector const cp1(ba.cross(p1 - a));
Vector const cp2(ba.cross(p2 - a));
return cp1.dot(cp2) >= 0.0f;
}
}
bool Vector::inPolygon (const Vector& v0, const Vector& v1, const Vector& v2) const
{
return sameSide(*this, v0, v1, v2) && sameSide(*this, v1, v2, v0) && sameSide(*this, v2, v0, v1);
}
// ----------------------------------------------------------------------
/**
* Test whether a point lies within a convex n-sided polygon.
*
* This should be on at least the plane for the test to work. See Plane::findIntersection ()
*/
bool Vector::inPolygon(const std::vector<Vector> &convexPolygonVertices) const
{
// @todo optimize this
const uint numberOfConvexPolygonVertices = convexPolygonVertices.size();
for (uint i = 1; i < numberOfConvexPolygonVertices-1; ++i)
if (inPolygon(convexPolygonVertices[0], convexPolygonVertices[i], convexPolygonVertices[i+1]))
return true;
return false;
}
// ----------------------------------------------------------------------
/**
* Determine if two vectors are within an epsilon distance.
* The epsilon distance is tested for all three dimensions, not a
* distance between the points.
*
* @param rhs The second vector to compare.
* @param epsilon The epsilon distance.
*/
bool Vector::withinEpsilon(const Vector &rhs, float epsilon) const
{
return (abs(x - rhs.x) < epsilon) && (abs(y - rhs.y) < epsilon) && (abs(z - rhs.z) < epsilon);
}
// ----------------------------------------------------------------------
/**
* Find a direction which is perpendicular to the vector passed in.
* NOTE: The result is NOT guaranteed to be normalized.
*/
const Vector Vector::perpendicular(Vector const & direction)
{
// Measure the projection of "direction" onto each of the axes
float const id = abs(direction.dot(Vector::unitX));
float const jd = abs(direction.dot(Vector::unitY));
float const kd = abs(direction.dot(Vector::unitZ));
Vector result;
if (id <= jd && id <= kd)
// Projection onto i was the smallest
result = direction.cross(Vector::unitX);
else if (jd <= id && jd <= kd)
// Projection onto j was the smallest
result = direction.cross(Vector::unitY);
else
// Projection onto k was the smallest
result = direction.cross(Vector::unitZ);
result.normalize();
return result;
}
// ======================================================================
@@ -0,0 +1,716 @@
// ======================================================================
//
// Vector.h
// Portions copyright 1998 Bootprint Entertainment.
// Portions copyright 2000-2001 Sony Online Entertainment.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_Vector_H
#define INCLUDED_Vector_H
// ======================================================================
class Vector
{
public:
// Vector 1,0,0
static const Vector unitX;
// Vector 0,1,0
static const Vector unitY;
// Vector 0,0,1
static const Vector unitZ;
// Vector -1,0,0
static const Vector negativeUnitX;
// Vector 0,-1,0
static const Vector negativeUnitY;
// Vector 0,0,-1
static const Vector negativeUnitZ;
// Vector 0,0,0
static const Vector zero;
// Vector 1,1,1
static const Vector xyz111;
// Vector max, max, max
static const Vector maxXYZ;
// Vector -maxXYZ
static const Vector negativeMaxXYZ;
// minimum vector magnitude to normalize
static const real NORMALIZE_THRESHOLD;
// A vector is normalized if its magnitude is within NORMALIZED_EPSILON of 1.
static const real NORMALIZED_EPSILON;
public:
// x-component of the 3d vector
real x; //lint !e1925 // Public data member
// y-component of the 3d vector
real y; //lint !e1925 // Public data member
// z-component of the 3d vector
real z; //lint !e1925 // Public data member
public:
Vector(void);
Vector(real newX, real newY, real newZ);
void debugPrint(const char *header) const;
void set(real newX, real newY, real newZ);
void makeZero(void);
bool normalize(void);
bool approximateNormalize(void);
bool isNormalized(void) const;
const Vector findClosestPointOnLine(const Vector &line0, const Vector &line1) const;
const Vector findClosestPointOnLine(const Vector &line0, const Vector &line1, real *t) const;
const Vector findClosestPointOnLineSegment(const Vector & startPoint, const Vector & endPoint) const;
real distanceToLine(const Vector &line0, const Vector &line1) const;
real distanceToLineSegment(const Vector &line0, const Vector &line1) const;
real theta(void) const;
real phi(void) const;
real dot(const Vector &vector) const;
const Vector cross(const Vector &rhs) const;
real magnitudeSquared(void) const;
real approximateMagnitude(void) const;
real magnitude(void) const;
real magnitudeBetween(const Vector &vector) const;
real magnitudeBetweenSquared(const Vector &vector) const;
real magnitudeXYBetween(const Vector &vector) const;
real magnitudeXYBetweenSquared(const Vector &vector) const;
real magnitudeXZBetween(const Vector &vector) const;
real magnitudeXZBetweenSquared(const Vector &vector) const;
real magnitudeYZBetween(const Vector &vector) const;
real magnitudeYZBetweenSquared(const Vector &vector) const;
const Vector operator -(void) const;
Vector &operator -=(const Vector &rhs);
Vector &operator +=(const Vector &rhs);
Vector &operator /=(real scalar);
Vector &operator *=(real scalar);
const Vector operator +(const Vector &rhs) const;
const Vector operator -(const Vector &rhs) const;
const Vector operator *(real scalar) const;
const Vector operator /(real scalar) const;
friend const Vector operator *(real scalar, const Vector &vector);
bool operator ==(const Vector &rhs) const;
bool operator !=(const Vector &rhs) const;
bool withinEpsilon(const Vector &rhs, float epsilon) const;
const Vector reflectIncoming(const Vector &incident) const;
const Vector reflectOutgoing(const Vector &incident) const;
// const Vector refract(const Vector &normal, real n1, real n2);
bool inPolygon (const Vector& v0, const Vector& v1, const Vector& v2) const;
bool inPolygon (const stdvector<Vector>::fwd &convexPolygonVertices) const;
public:
static const Vector midpoint(const Vector &vector1, const Vector &vector2);
static const Vector linearInterpolate(const Vector &begin, const Vector &end, real t);
static const Vector randomUnit(void);
static const Vector randomCube(real halfSideLength=CONST_REAL(1));
static const Vector perpendicular(Vector const & direction);
};
// ======================================================================
// Construct a vector
//
// Remarks:
//
// Initializes the components to 0.
inline Vector::Vector(void)
: x(CONST_REAL(0)), y(CONST_REAL(0)), z(CONST_REAL(0))
{
}
// ----------------------------------------------------------------------
/**
* Construct a vector.
*
* Initializes the components to the specified values
*
* @param newX Value for the X component
* @param newY Value for the Y component
* @param newZ Value for the Z component
*/
inline Vector::Vector(real newX, real newY, real newZ)
: x(newX), y(newY), z(newZ)
{
}
// ----------------------------------------------------------------------
/**
* Set the vector components to new values.
*
* @param newX Value for the X component
* @param newY Value for the Y component
* @param newZ Value for the Z component
*/
inline void Vector::set(real newX, real newY, real newZ)
{
x = newX;
y = newY;
z = newZ;
}
// ----------------------------------------------------------------------
/**
* Set all the vector components to zero.
*/
inline void Vector::makeZero(void)
{
x = CONST_REAL(0);
y = CONST_REAL(0);
z = CONST_REAL(0);
}
// ----------------------------------------------------------------------
/**
* Return the rotation of the vector around the Y plane.
*
* The result is undefined if both the x and z values of the vector are zero.
*
* This routine uses atan2() so it is not particularly fast.
*
* @return The rotation of the vector around the Y plane
*/
inline real Vector::theta(void) const
{
return atan2(x, z);
}
// ----------------------------------------------------------------------
/**
* Calculate the angle of the vector from the X-Z plane.
*
* This routine uses sqrt() and atan2() so it is not particularly fast.
*
* @return The angle of the vector from the X-Z plane
*/
inline real Vector::phi(void) const
{
return atan2(-y, sqrt(sqr(x) + sqr(z)));
}
// ----------------------------------------------------------------------
/**
* Compute the dot product between this vector and another vector.
*
* The dot product value is equal to the cosine of the angle between
* the two vectors multiplied by the sum of the lengths of the vectors.
*
* @param vector Vector to compute the dot product against
*/
inline real Vector::dot(const Vector &vec) const
{
return (x * vec.x) + (y * vec.y) + (z * vec.z);
}
// ----------------------------------------------------------------------
/**
* Calculate the square of the magnitude of this vector.
*
* This routine is much faster than magnitude().
*
* @return The square of the magnitude of the vector
* @see Vector::magnitude()
*/
inline real Vector::magnitudeSquared(void) const
{
return (sqr(x) + sqr(y) + sqr(z));
}
// ----------------------------------------------------------------------
/**
* Calculate the approximate magnitude of this vector.
*
* The implementation of this routine has +/- 8% error.
*
* @return The approximate magnitude of the vector
*/
inline real Vector::approximateMagnitude(void) const
{
real minc = abs(x);
real midc = abs(y);
real maxc = abs(z);
// sort the vectors
// we do our own swapping to avoid heavy-weight includes in such a low-level class
if (midc < minc)
{
const real temp = midc;
midc = minc;
minc = temp;
}
if (maxc < minc)
{
const real temp = maxc;
maxc = minc;
minc = temp;
}
if (maxc < midc)
{
const real temp = maxc;
maxc = midc;
midc = temp;
}
return (maxc + CONST_REAL(11.0f / 32.0f) * midc + CONST_REAL(0.25f) * minc);
}
// ----------------------------------------------------------------------
/**
* Calculate the magnitude of this vector.
*
* This routine is slow because it requires a square root operation.
*
* @return The magnitude of the vector
* @see Vector::magnitudeSquared()
*/
inline real Vector::magnitude(void) const
{
return sqrt(magnitudeSquared());
}
// ----------------------------------------------------------------------
/**
* Calculate the square of the magnitude of the vector between this vector and the specified vector.
*
* This routine is much faster than magnitudeBetween().
*
* @param vector The other endpoint of the delta vector
* @return The square of the magnitude of the delta vector
* @see Vector::magnitudeBetween()
*/
inline real Vector::magnitudeBetweenSquared(const Vector &vec) const
{
return (sqr(x - vec.x) + sqr(y - vec.y) + sqr(z - vec.z));
}
// ----------------------------------------------------------------------
/**
* Calculate the magnitude of the vector between this vector and the specified vector.
*
* This routine is much slower than magnitudeBetweenSquared().
*
* @param vector The other endpoint of the delta vector
* @return The magnitude of the delta vector
* @see Vector::magnitudeBetweenSquared()
*/
inline real Vector::magnitudeBetween(const Vector &vec) const
{
return sqrt(magnitudeBetweenSquared(vec));
}
// ----------------------------------------------------------------------
/**
* Calculate the square of the magnitude of the vector between this vector and the specified vector.
*
* This routine is much faster than magnitudeBetween().
*
* @param vector The other endpoint of the delta vector
* @return The square of the magnitude of the delta vector
* @see Vector::magnitudeBetween()
*/
inline real Vector::magnitudeXYBetweenSquared(const Vector &vec) const
{
return (sqr(x - vec.x) + sqr(y - vec.y));
}
// ----------------------------------------------------------------------
/**
* Calculate the magnitude of the vector between this vector and the specified vector.
*
* This routine is much slower than magnitudeBetweenSquared().
*
* @param vector The other endpoint of the delta vector
* @return The magnitude of the delta vector
* @see Vector::magnitudeBetweenSquared()
*/
inline real Vector::magnitudeXYBetween(const Vector &vec) const
{
return sqrt(magnitudeXYBetweenSquared(vec));
}
// ----------------------------------------------------------------------
/**
* Calculate the square of the magnitude of the vector between this vector and the specified vector.
*
* This routine is much faster than magnitudeBetween().
*
* @param vector The other endpoint of the delta vector
* @return The square of the magnitude of the delta vector
* @see Vector::magnitudeBetween()
*/
inline real Vector::magnitudeXZBetweenSquared(const Vector &vec) const
{
return (sqr(x - vec.x) + sqr(z - vec.z));
}
// ----------------------------------------------------------------------
/**
* Calculate the magnitude of the vector between this vector and the specified vector.
*
* This routine is much slower than magnitudeBetweenSquared().
*
* @param vector The other endpoint of the delta vector
* @return The magnitude of the delta vector
* @see Vector::magnitudeBetweenSquared()
*/
inline real Vector::magnitudeXZBetween(const Vector &vec) const
{
return sqrt(magnitudeXZBetweenSquared(vec));
}
// ----------------------------------------------------------------------
/**
* Calculate the square of the magnitude of the vector between this vector and the specified vector.
*
* This routine is much faster than magnitudeBetween().
*
* @param vector The other endpoint of the delta vector
* @return The square of the magnitude of the delta vector
* @see Vector::magnitudeBetween()
*/
inline real Vector::magnitudeYZBetweenSquared(const Vector &vec) const
{
return (sqr(y - vec.y) + sqr(z - vec.z));
}
// ----------------------------------------------------------------------
/**
* Calculate the magnitude of the vector between this vector and the specified vector.
*
* This routine is much slower than magnitudeBetweenSquared().
*
* @param vector The other endpoint of the delta vector
* @return The magnitude of the delta vector
* @see Vector::magnitudeBetweenSquared()
*/
inline real Vector::magnitudeYZBetween(const Vector &vec) const
{
return sqrt(magnitudeYZBetweenSquared(vec));
}
// ----------------------------------------------------------------------
/**
* Reverse the direction of the vector.
*
* This routine simple negates each component of the vector
*/
inline const Vector Vector::operator -(void) const
{
return Vector(-x, -y, -z);
}
// ----------------------------------------------------------------------
/**
* Subtract a vector from this vector and store the result back in this vector.
*
* This is the basic obvious -= operator overloaded for vectors
*
* @param rhs The vector to subtract from this vector
* @return A reference to this modified vector
*/
inline Vector &Vector::operator -=(const Vector &rhs)
{
x -= rhs.x;
y -= rhs.y;
z -= rhs.z;
return *this;
}
// ----------------------------------------------------------------------
/**
* Add a vector from this vector and store the result back in this vector.
*
* This is the basic obvious += operator overloaded for vectors.
*
* @param rhs The vector to add to this vector
* @return A reference to this modified vector
*/
inline Vector &Vector::operator +=(const Vector &rhs)
{
x += rhs.x;
y += rhs.y;
z += rhs.z;
return *this;
}
// ----------------------------------------------------------------------
/**
* Multiply this vector by a scalar.
*
* This is the basic obvious *= operator overloaded for vectors and scalars.
*
* @param scalar The vector to subtract from this vector
* @return A reference to this modified vector
*/
inline Vector &Vector::operator *=(real scalar)
{
x *= scalar;
y *= scalar;
z *= scalar;
return *this;
}
// ----------------------------------------------------------------------
/**
* Divide this vector by a scalar.
*
* This is the basic obvious /= operator overloaded for vectors and scalars.
*
* @param scalar The vector to subtract from this vector
* @return A reference to this modified vector
*/
inline Vector &Vector::operator /=(real scalar)
{
*this *= (CONST_REAL(1.0) / scalar);
return *this;
}
// ----------------------------------------------------------------------
/**
* Calculate the cross product between two vectors.
*
* This routine returns a temporary.
*
* Cross products are not communitive.
*
* @param rhs The right-hand size of the expression
* @return A vector that is the result of the cross product of the two vectors.
*/
inline const Vector Vector::cross(const Vector &rhs) const
{
return Vector(y * rhs.z - z * rhs.y, z * rhs.x - x * rhs.z, x * rhs.y - y * rhs.x);
}
// ----------------------------------------------------------------------
/**
* Add two vectors.
*
* This routine returns a temporary.
*
* @param rhs The right-hand size of the expression
* @return A vector that is the sum of the two arguments.
*/
inline const Vector Vector::operator +(const Vector &rhs) const
{
return Vector(x + rhs.x, y + rhs.y, z + rhs.z);
}
// ----------------------------------------------------------------------
/**
* Subtract two vectors.
*
* This routine returns a temporary.
*
* @param rhs The right-hand size of the expression
* @return A vector that is the result of the left-hand-side minus the right-hand-side
*/
inline const Vector Vector::operator -(const Vector &rhs) const
{
return Vector(x - rhs.x, y - rhs.y, z - rhs.z);
}
// ----------------------------------------------------------------------
/**
* Multiply a vector by a scalar.
*
* This routine returns a temporary.
*
* @param scalar The scalar to multiply by
* @return The source vector multiplied by the scalar
*/
inline const Vector Vector::operator *(real scalar) const
{
return Vector(x * scalar, y * scalar, z * scalar);
}
// ----------------------------------------------------------------------
/**
* Divide a vector by a scalar.
*
* This routine returns a temporary.
*
* @param scalar The scalar to multiply by
* @return The source vector divided by the scalar
*/
inline const Vector Vector::operator /(real scalar) const
{
const real multiplier(CONST_REAL(1.0) / scalar);
return Vector(x * multiplier, y * multiplier, z * multiplier);
}
// ----------------------------------------------------------------------
/**
* Multiply a vector by a scalar.
*
* This routine returns a temporary.
*
* @return The source vector multiplied by the scalar
*/
inline const Vector operator *(real scalar, const Vector &vec)
{
return Vector(vec.x * scalar, vec.y * scalar, vec.z * scalar);
}
// ----------------------------------------------------------------------
/**
* Test two vectors for equality.
*
* Floating-point math make may two very similiar expressions end up slightly
* different, thus showing inequality when the result is very, very close.
*
* @param rhs The right-hand size of the expression
* @return True if the vectors are exactly equal, otherwise false.
*/
inline bool Vector::operator ==(const Vector &rhs) const
{
return (x == rhs.x && y == rhs.y && z == rhs.z); //lint !e777 // Testing floats for equality
}
// ----------------------------------------------------------------------
/**
* Test two vectors for inequality.
*
* Floating-point math make may two very similiar expressions end up slightly
* different, thus showing inequality when the result is very, very close.
*
* @param rhs The right-hand size of the expression
* @return True if the vectors are not equal, otherwise false.
*/
inline bool Vector::operator !=(const Vector &rhs) const
{
return (x != rhs.x || y != rhs.y || z != rhs.z); //lint !e777 // Testing floats for equality
}
// ----------------------------------------------------------------------
/**
* Reflect an outgoing vector around this normal.
*
* This routine assumes that both this vector and the normal around which it
* is being reflected have the same origin (the dot product of the normal and
* the vertex is positive)
*
* @param incident Normal to reflect this vector around
* @return The reflected vector
*/
inline const Vector Vector::reflectOutgoing(const Vector &incident) const
{
const Vector &normal = *this;
return normal * (2 * normal.dot(incident)) - incident;
}
// ----------------------------------------------------------------------
/**
* Reflect an incoming vector around this normal.
*
* This routine assumes that the vector terminates at the normal
* (the dot product of the normal and the vertex is negative).
*
* @param incident Normal to reflect this vector around
* @return The reflected vector
*/
inline const Vector Vector::reflectIncoming(const Vector &incident) const
{
return reflectOutgoing(-incident);
}
// ----------------------------------------------------------------------
/**
* Compute the midpoint of two vectors.
*
* This routine just averages the three components separately.
*
* @param vector1 First endpoint
* @param vector2 Second endpoint
*/
inline const Vector Vector::midpoint(const Vector &vector1, const Vector &vector2)
{
return Vector((vector1.x + vector2.x) * CONST_REAL(0.5), (vector1.y + vector2.y) * CONST_REAL(0.5), (vector1.z + vector2.z) * CONST_REAL(0.5));
}
// ----------------------------------------------------------------------
/**
* Linearly interpolate between two vectors.
*
* The time parameter should be between 0.0 and 1.0 inclusive in order to have
* the result be between the two endpoints. At time 0.0 the result will be
* vector1, and at time 1.0 the result will be vector2.
*
* @param vector1 Starting endpoint
* @param vector2 Terminating endpoint
* @param time
*/
inline const Vector Vector::linearInterpolate(const Vector &vector1, const Vector &vector2, real time)
{
return Vector(vector1.x + (vector2.x - vector1.x) * time, vector1.y + (vector2.y - vector1.y) * time, vector1.z + (vector2.z - vector1.z) * time);
}
// ======================================================================
#endif
@@ -0,0 +1,310 @@
//===================================================================
//
// Vector2d.h
// asommers 7-26-99
//
// copyright 1999, bootprint entertainment
//
//===================================================================
#ifndef INCLUDED_Vector2d_H
#define INCLUDED_Vector2d_H
//===================================================================
class Vector2d
{
public:
float x;
float y;
public:
Vector2d ();
Vector2d (float newX, float newY);
void set (float newX, float newY);
void makeZero ();
bool isZero () const;
bool normalize ();
float dot (const Vector2d& vector) const;
float theta () const;
void rotate (float radians);
void rotate (float radians, const Vector2d& center);
const Vector2d operator- () const;
const Vector2d operator+ (const Vector2d& rhs) const;
const Vector2d operator- (const Vector2d& rhs) const;
const Vector2d operator* (float scalar) const;
const Vector2d operator/ (float scalar) const;
bool operator== (const Vector2d& rhs) const;
bool operator!= (const Vector2d& rhs) const;
Vector2d& operator+= (const Vector2d& rhs);
Vector2d& operator-= (const Vector2d& rhs);
Vector2d& operator*= (float scalar);
Vector2d& operator/= (float scalar);
float magnitude () const;
float magnitudeSquared () const;
float magnitudeBetween (const Vector2d& vector) const;
float magnitudeBetweenSquared (const Vector2d& vector) const;
static const Vector2d linearInterpolate (const Vector2d& start, const Vector2d& end, float t);
static const Vector2d normalized (const Vector2d& vector, bool* result=0);
static const Vector2d normal (const Vector2d& vector, bool normalize, bool* result=0);
};
//===================================================================
inline Vector2d::Vector2d () :
x (0),
y (0)
{
}
//-------------------------------------------------------------------
inline Vector2d::Vector2d (float newX, float newY) :
x (newX),
y (newY)
{
}
//-------------------------------------------------------------------
inline void Vector2d::set (float newX, float newY)
{
x = newX;
y = newY;
}
//-------------------------------------------------------------------
inline void Vector2d::makeZero ()
{
x = 0;
y = 0;
}
//-------------------------------------------------------------------
inline bool Vector2d::isZero () const
{
return x == 0 && y == 0;
}
//-------------------------------------------------------------------
inline bool Vector2d::normalize ()
{
const float mag = magnitude ();
if (mag < 0.00001f)
return false;
*this /= mag;
return true;
}
//-------------------------------------------------------------------
inline float Vector2d::dot (const Vector2d& vector) const
{
return (x * vector.x) + (y * vector.y);
}
//-------------------------------------------------------------------
inline float Vector2d::theta () const
{
return atan2(x, y);
}
//-------------------------------------------------------------------
inline void Vector2d::rotate (float radians)
{
const float cosAngle = cos (radians);
const float sinAngle = sin (radians);
const float oldX = x;
const float oldY = y;
x = oldX * cosAngle - oldY * sinAngle;
y = oldX * sinAngle + oldY * cosAngle;
}
//-------------------------------------------------------------------
inline void Vector2d::rotate (float radians, const Vector2d& origin)
{
const Vector2d point (x - origin.x, y - origin.y);
const float cosAngle = cos (radians);
const float sinAngle = sin (radians);
x = origin.x + point.x * cosAngle - point.y * sinAngle;
y = origin.y + point.x * sinAngle + point.y * cosAngle;
}
//-------------------------------------------------------------------
inline const Vector2d Vector2d::operator- () const
{
return Vector2d (-x, -y);
}
//-------------------------------------------------------------------
inline const Vector2d Vector2d::operator+ (const Vector2d& rhs) const
{
return Vector2d (x + rhs.x, y + rhs.y);
}
//-------------------------------------------------------------------
inline const Vector2d Vector2d::operator- (const Vector2d& rhs) const
{
return Vector2d (x - rhs.x, y - rhs.y);
}
//-------------------------------------------------------------------
inline const Vector2d Vector2d::operator* (float scalar) const
{
return Vector2d (x * scalar, y * scalar);
}
//-------------------------------------------------------------------
inline const Vector2d Vector2d::operator/ (float scalar) const
{
return operator* (RECIP (scalar));
}
//-------------------------------------------------------------------
inline bool Vector2d::operator== (const Vector2d& rhs) const
{
return x == rhs.x && y == rhs.y;
}
//-------------------------------------------------------------------
inline bool Vector2d::operator!= (const Vector2d& rhs) const
{
return !operator== (rhs);
}
//-------------------------------------------------------------------
inline float Vector2d::magnitude () const
{
return static_cast<float> (sqrt (magnitudeSquared ()));
}
//-------------------------------------------------------------------
inline float Vector2d::magnitudeSquared () const
{
return sqr (x) + sqr (y);
}
//-------------------------------------------------------------------
inline float Vector2d::magnitudeBetween (const Vector2d& vector) const
{
return static_cast<float> (sqrt (magnitudeBetweenSquared (vector)));
}
//-------------------------------------------------------------------
inline float Vector2d::magnitudeBetweenSquared (const Vector2d& vector) const
{
return sqr (x - vector.x) + sqr (y - vector.y);
}
//-------------------------------------------------------------------
inline Vector2d& Vector2d::operator+= (const Vector2d& rhs)
{
x += rhs.x;
y += rhs.y;
return *this;
}
//-------------------------------------------------------------------
inline Vector2d& Vector2d::operator-= (const Vector2d& rhs)
{
x -= rhs.x;
y -= rhs.y;
return *this;
}
//-------------------------------------------------------------------
inline Vector2d& Vector2d::operator*= (float scalar)
{
x *= scalar;
y *= scalar;
return *this;
}
//-------------------------------------------------------------------
inline Vector2d& Vector2d::operator/= (float scalar)
{
*this *= RECIP (scalar);
return *this;
}
//-------------------------------------------------------------------
inline const Vector2d Vector2d::linearInterpolate (const Vector2d& start, const Vector2d& end, float t)
{
Vector2d v;
v.x = ::linearInterpolate (start.x, end.x, t);
v.y = ::linearInterpolate (start.y, end.y, t);
return v;
}
//-------------------------------------------------------------------
inline const Vector2d Vector2d::normalized (const Vector2d& vector, bool* result)
{
Vector2d v = vector;
bool r = v.normalize ();
if (result)
*result = r;
return v;
}
//-------------------------------------------------------------------
inline const Vector2d Vector2d::normal (const Vector2d& vector, bool normalize, bool* result)
{
Vector2d v (-vector.y, vector.x);
if (normalize)
{
bool r = v.normalize ();
if (result)
*result = r;
}
return v;
}
//===================================================================
#endif
@@ -0,0 +1,39 @@
// ======================================================================
//
// VectorArgb.h
// jeff grills
//
// copyright 1999 Bootprint Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/VectorArgb.h"
#include "sharedMath/PackedArgb.h"
// ======================================================================
const VectorArgb VectorArgb::solidBlack (CONST_REAL(1), CONST_REAL(0), CONST_REAL(0), CONST_REAL(0));
const VectorArgb VectorArgb::solidBlue (CONST_REAL(1), CONST_REAL(0), CONST_REAL(0), CONST_REAL(1));
const VectorArgb VectorArgb::solidCyan (CONST_REAL(1), CONST_REAL(0), CONST_REAL(1), CONST_REAL(1));
const VectorArgb VectorArgb::solidGreen (CONST_REAL(1), CONST_REAL(0), CONST_REAL(1), CONST_REAL(0));
const VectorArgb VectorArgb::solidRed (CONST_REAL(1), CONST_REAL(1), CONST_REAL(0), CONST_REAL(0));
const VectorArgb VectorArgb::solidMagenta(CONST_REAL(1), CONST_REAL(1), CONST_REAL(0), CONST_REAL(1));
const VectorArgb VectorArgb::solidYellow (CONST_REAL(1), CONST_REAL(1), CONST_REAL(1), CONST_REAL(0));
const VectorArgb VectorArgb::solidWhite (CONST_REAL(1), CONST_REAL(1), CONST_REAL(1), CONST_REAL(1));
const VectorArgb VectorArgb::solidGray (CONST_REAL(1), CONST_REAL(0.5), CONST_REAL(0.5), CONST_REAL(0.5));
const real oo255 = 1.0f / 255.0f;
// ======================================================================
VectorArgb::VectorArgb(const PackedArgb &argb)
: a(static_cast<float>(argb.getA()) * oo255),
r(static_cast<float>(argb.getR()) * oo255),
g(static_cast<float>(argb.getG()) * oo255),
b(static_cast<float>(argb.getB()) * oo255)
{
}
// ======================================================================
@@ -0,0 +1,155 @@
// ======================================================================
//
// VectorArgb.h
// Portions Copyright 1998 Bootprint Entertainment
// Portions Copyright 2003 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_VectorArgb_H
#define INCLUDED_VectorArgb_H
// ======================================================================
class PackedArgb;
// ======================================================================
class VectorArgb
{
public:
static const VectorArgb solidBlack;
static const VectorArgb solidBlue;
static const VectorArgb solidCyan;
static const VectorArgb solidGray;
static const VectorArgb solidGreen;
static const VectorArgb solidRed;
static const VectorArgb solidMagenta;
static const VectorArgb solidYellow;
static const VectorArgb solidWhite;
real a;
real r;
real g;
real b;
VectorArgb(void);
VectorArgb(real newA, real newR, real newG, real newB);
VectorArgb(const PackedArgb &argb);
void set(real newA, real newR, real newG, real newB);
float rgbIntensity() const;
bool operator ==(const VectorArgb &rhs) const;
bool operator !=(const VectorArgb &rhs) const;
const VectorArgb operator *(float scalar) const;
VectorArgb operator+(const VectorArgb &o) const { return VectorArgb(a+o.a, r+o.r, g+o.g, b+o.b); }
static const VectorArgb linearInterpolate(const VectorArgb &color1, const VectorArgb &color2, real time);
uint32 convertToUint32() const;
uint32 convertToUint32NoClamp() const;
};
// ======================================================================
inline VectorArgb::VectorArgb(void)
: a(CONST_REAL(1)),
r(CONST_REAL(0)),
g(CONST_REAL(0)),
b(CONST_REAL(0))
{
}
// ----------------------------------------------------------------------
inline VectorArgb::VectorArgb(real newA, real newR, real newG, real newB)
: a(newA),
r(newR),
g(newG),
b(newB)
{
}
// ----------------------------------------------------------------------
inline void VectorArgb::set(real newA, real newR, real newG, real newB)
{
a = newA;
r = newR;
g = newG;
b = newB;
}
// ----------------------------------------------------------------------
inline bool VectorArgb::operator ==(const VectorArgb &rhs) const
{
return ((a == rhs.a) && (r == rhs.r) && (g == rhs.g) && (b == rhs.b)); //lint !e777 // testing floats for equality
}
// ----------------------------------------------------------------------
inline bool VectorArgb::operator !=(const VectorArgb &rhs) const
{
return !(*this == rhs);
}
// ----------------------------------------------------------------------
inline float VectorArgb::rgbIntensity() const
{
return abs(r) * 0.30f + abs(g) * 0.59f + abs(b) * 0.11f;
}
// ----------------------------------------------------------------------
/**
* Linearly interpolate between two VectorArgbs.
*
* The time parameter should be between 0.0 and 1.0 inclusive in order to have
* the result be between the two endpoints. At time 0.0 the result will be
* color1, and at time 1.0 the result will be color2.
*
* @param color1 Starting endpoint
* @param color2 Terminating endpoint
* @param time
*/
inline const VectorArgb VectorArgb::linearInterpolate(const VectorArgb &color1, const VectorArgb &color2, real time)
{
return VectorArgb(color1.a + (color2.a - color1.a) * time, color1.r + (color2.r - color1.r) * time, color1.g + (color2.g - color1.g) * time, color1.b + (color2.b - color1.b) * time);
}
// ----------------------------------------------------------------------
inline uint32 VectorArgb::convertToUint32() const
{
const uint32 a32 = clamp(static_cast<uint32>(0), static_cast<uint32>(a * 255.0f), static_cast<uint32>(255));
const uint32 r32 = clamp(static_cast<uint32>(0), static_cast<uint32>(r * 255.0f), static_cast<uint32>(255));
const uint32 g32 = clamp(static_cast<uint32>(0), static_cast<uint32>(g * 255.0f), static_cast<uint32>(255));
const uint32 b32 = clamp(static_cast<uint32>(0), static_cast<uint32>(b * 255.0f), static_cast<uint32>(255));
return (a32 << 24) | (r32 << 16) | (g32 << 8) | (b32 << 0);
}
// ----------------------------------------------------------------------
inline uint32 VectorArgb::convertToUint32NoClamp() const
{
const uint32 a32 = static_cast<uint32>(a * 255.0f);
const uint32 r32 = static_cast<uint32>(r * 255.0f);
const uint32 g32 = static_cast<uint32>(g * 255.0f);
const uint32 b32 = static_cast<uint32>(b * 255.0f);
return (a32 << 24) | (r32 << 16) | (g32 << 8) | (b32 << 0);
}
// ----------------------------------------------------------------------
inline const VectorArgb VectorArgb::operator *(const float scalar) const
{
return VectorArgb(a * scalar, r * scalar, g * scalar, b * scalar);
}
// ======================================================================
#endif
@@ -0,0 +1,44 @@
// ======================================================================
//
// VectorRgba.h
//
// Portions Copyright 1999 Bootprint Entertainment
// Portions Copyright 2004 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/VectorRgba.h"
#include "sharedMath/PackedArgb.h"
// ======================================================================
const VectorRgba VectorRgba::solidBlack (0.0f, 0.0f, 0.0f, 1.0f);
const VectorRgba VectorRgba::solidBlue (0.0f, 0.0f, 1.0f, 1.0f);
const VectorRgba VectorRgba::solidCyan (0.0f, 1.0f, 1.0f, 1.0f);
const VectorRgba VectorRgba::solidGreen (0.0f, 1.0f, 0.0f, 1.0f);
const VectorRgba VectorRgba::solidRed (1.0f, 0.0f, 0.0f, 1.0f);
const VectorRgba VectorRgba::solidMagenta(1.0f, 0.0f, 1.0f, 1.0f);
const VectorRgba VectorRgba::solidYellow (1.0f, 1.0f, 0.0f, 1.0f);
const VectorRgba VectorRgba::solidWhite (1.0f, 1.0f, 1.0f, 1.0f);
const VectorRgba VectorRgba::solidGray (0.5f, 0.5f, 0.5f, 1.0f);
namespace VectorRgbaNamespace
{
const real oo255 = 1.0f / 255.0f;
}
using namespace VectorRgbaNamespace;
// ======================================================================
VectorRgba::VectorRgba(PackedArgb const & argb)
:
r(static_cast<float>(argb.getR()) * oo255),
g(static_cast<float>(argb.getG()) * oo255),
b(static_cast<float>(argb.getB()) * oo255),
a(static_cast<float>(argb.getA()) * oo255)
{
}
// ======================================================================
@@ -0,0 +1,148 @@
// ======================================================================
//
// VectorRgba.h
// Portions Copyright 1998 Bootprint Entertainment
// Portions Copyright 2003-2004 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_VectorRgba_H
#define INCLUDED_VectorRgba_H
// ======================================================================
class PackedArgb;
// ======================================================================
class VectorRgba
{
public:
static const VectorRgba solidBlack;
static const VectorRgba solidBlue;
static const VectorRgba solidCyan;
static const VectorRgba solidGray;
static const VectorRgba solidGreen;
static const VectorRgba solidRed;
static const VectorRgba solidMagenta;
static const VectorRgba solidYellow;
static const VectorRgba solidWhite;
public:
float r;
float g;
float b;
float a;
public:
VectorRgba();
VectorRgba(float newR, float newG, float newB, float newA);
VectorRgba(PackedArgb const & argb);
void set(float newR, float newG, float newB, float newA);
float rgbIntensity() const;
bool operator ==(VectorRgba const & rhs) const;
bool operator !=(VectorRgba const & rhs) const;
VectorRgba const operator *(float scalar) const;
static VectorRgba const linearInterpolate(VectorRgba const & color1, VectorRgba const & color2, float time);
uint32 convertToUint32() const;
};
// ======================================================================
inline VectorRgba::VectorRgba()
:
r(0.0f),
g(0.0f),
b(0.0f),
a(1.0f)
{
}
// ----------------------------------------------------------------------
inline VectorRgba::VectorRgba(float const newR, float const newG, float const newB, float const newA)
:
r(newR),
g(newG),
b(newB),
a(newA)
{
}
// ----------------------------------------------------------------------
inline void VectorRgba::set(float const newR, float const newG, float const newB, float const newA)
{
r = newR;
g = newG;
b = newB;
a = newA;
}
// ----------------------------------------------------------------------
inline bool VectorRgba::operator ==(VectorRgba const & rhs) const
{
return ((r == rhs.r) && (g == rhs.g) && (b == rhs.b) && (a == rhs.a)); //lint !e777 // testing floats for equality
}
// ----------------------------------------------------------------------
inline bool VectorRgba::operator !=(VectorRgba const & rhs) const
{
return !(*this == rhs);
}
// ----------------------------------------------------------------------
inline float VectorRgba::rgbIntensity() const
{
return abs(r) * 0.30f + abs(g) * 0.59f + abs(b) * 0.11f;
}
// ----------------------------------------------------------------------
/**
* Linearly interpolate between two VectorRgbas.
*
* The time parameter should be between 0.0 and 1.0 inclusive in order to have
* the result be between the two endpoints. At time 0.0 the result will be
* color1, and at time 1.0 the result will be color2.
*
* @param color1 Starting endpoint
* @param color2 Terminating endpoint
* @param time
*/
inline VectorRgba const VectorRgba::linearInterpolate(VectorRgba const & color1, VectorRgba const & color2, float time)
{
return VectorRgba(color1.r + (color2.r - color1.r) * time, color1.g + (color2.g - color1.g) * time, color1.b + (color2.b - color1.b) * time, color1.a + (color2.a - color1.a) * time);
}
// ----------------------------------------------------------------------
inline uint32 VectorRgba::convertToUint32() const
{
const uint32 a32 = clamp(static_cast<uint32>(0), static_cast<uint32>(a * 255.0f), static_cast<uint32>(255));
const uint32 r32 = clamp(static_cast<uint32>(0), static_cast<uint32>(r * 255.0f), static_cast<uint32>(255));
const uint32 g32 = clamp(static_cast<uint32>(0), static_cast<uint32>(g * 255.0f), static_cast<uint32>(255));
const uint32 b32 = clamp(static_cast<uint32>(0), static_cast<uint32>(b * 255.0f), static_cast<uint32>(255));
return (a32 << 24) | (r32 << 16) | (g32 << 8) | (b32 << 0);
}
// ----------------------------------------------------------------------
inline VectorRgba const VectorRgba::operator *(float const scalar) const
{
return VectorRgba(r * scalar, g * scalar, b * scalar, a * scalar);
}
// ======================================================================
#endif
@@ -0,0 +1,289 @@
// ======================================================================
//
// Volume.cpp
// copyright 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Volume.h"
#include "sharedMath/Plane.h"
#include "sharedMath/Sphere.h"
#include "sharedMath/Vector.h"
// ======================================================================
// Create an open-ended volume
//
// This constructor creates an open ended volume by projecting a ray from originPoint
// through all the vertices in vertexList, and capping the volume off with the plane
// formed by vertexList. This routine assumes the vertices in vertexList form a
// planar convex polygon and wind in a clockwise order.
//
// @param originPoint Point from which the volume is cast.
// @param numberOfVertices Number of vertices in vertexList.
// @param vertexList Co-planar set of points describing the siloutte edges of the volume.
Volume::Volume(const Vector &originPoint, const int numberOfVertices, const Vector * const vertexList)
:
m_numberOfPlanes(numberOfVertices + 1),
m_plane(new Plane[ static_cast<uint>(m_numberOfPlanes) ])
{
NOT_NULL(vertexList);
DEBUG_FATAL(numberOfVertices < 3, ("At least 3 vertices are necessary"));
// build the cap
m_plane[0].set(vertexList[0], vertexList[1], vertexList[2]);
// build the sides
for (int i = 1; i < numberOfVertices; ++i)
m_plane[i].set(originPoint, vertexList[i-1], vertexList[i]);
m_plane[numberOfVertices].set(originPoint, vertexList[numberOfVertices-1], vertexList[0]);
}
// ----------------------------------------------------------------------
/**
* Create an undefined volume
*
* This constructor creates a volume consisting of the specified number of planes,
* but does not set up the plane data.
*
* @param numberOfPlanes Number of planes in the volume.
*/
Volume::Volume(const int numberOfPlanes)
:
m_numberOfPlanes(numberOfPlanes),
m_plane(new Plane[ static_cast<uint>(m_numberOfPlanes) ])
{
}
// ----------------------------------------------------------------------
/**
* Construct a new volume from another, transformed by the specified transformation.
*
* @param other The other volume
* @param trans The transform to be applied.
*/
Volume::Volume (const Volume &rhs, const Transform &newTransform)
:
m_numberOfPlanes(rhs.m_numberOfPlanes),
m_plane(new Plane[ static_cast<uint>(m_numberOfPlanes) ])
{
for (int i = 0; i < m_numberOfPlanes; ++i)
m_plane [i].set(rhs.m_plane[i], newTransform);
}
// ----------------------------------------------------------------------
Volume::~Volume()
{
delete [] m_plane;
}
// ----------------------------------------------------------------------
/**
* Set a specific plane in the volume
*
* This routine can be used to build up a volume after having used the
* constructor that takes a number of planes.
*
* @param index The plane to modify.
* @param plane The new value for the plane data.
*/
void Volume::setPlane(const int index, const Plane &plane)
{
DEBUG_FATAL(index < 0 || index >= m_numberOfPlanes, ("index out of range %d/%d", index, m_numberOfPlanes));
m_plane[index] = plane;
}
// ----------------------------------------------------------------------
/**
* Set a specific plane in the volume
*
* This routine can be used to build up a volume after having used the
* constructor that takes a number of planes.
*
* @param index The plane to modify.
* @param plane The new value for the plane data.
*/
const Plane &Volume::getPlane(const int index) const
{
DEBUG_FATAL(index < 0 || index >= m_numberOfPlanes, ("index out of range %d/%d", index, m_numberOfPlanes));
return m_plane[index];
}
// ----------------------------------------------------------------------
/**
* Test a point against a volume
*
* @param point Point to test.
* @return True if the point is within the volume.
*/
bool Volume::contains(const Vector &point) const
{
for (int i = 0; i < m_numberOfPlanes; ++i)
if (m_plane[i].computeDistanceTo(point) > 0)
return false;
return true;
}
// ----------------------------------------------------------------------
/**
* See if the volume completely contains the sphere
*
* @param sphere The sphere to check.
* @return True if the entire sphere is within the volume, otherwise false.
*/
bool Volume::contains(const Sphere &sphere) const
{
const Vector &center = sphere.getCenter();
const real radius = sphere.getRadius();
for (int i = 0; i < m_numberOfPlanes; ++i)
if (m_plane[i].computeDistanceTo(center) > -radius)
return false;
return true;
}
// ----------------------------------------------------------------------
/**
* Test a point cloud against a volume
*
* @param pointCloud Point cloud to test.
* @param numberOfPoints Number of points in the point cloud.
* @return True if the point is within the volume.
*/
bool Volume::contains(const Vector *pointCloud, int numberOfPoints) const
{
NOT_NULL(pointCloud);
DEBUG_FATAL(numberOfPoints <= 0, ("numberOfPoints is less than 1"));
for (int i = 0; i < m_numberOfPlanes; ++i)
for (int j = 0; i < numberOfPoints; ++j)
if (m_plane[i].computeDistanceTo(pointCloud[j]) > 0)
return false;
return true;
}
// ----------------------------------------------------------------------
/**
* See if the volume intersects a sphere.
*
* The sphere is in the volume if any portion of it is within the volume.
*
* @param sphere The sphere to check.
* @return True if the any portion of the sphere is within the volume, otherwise false.
*/
bool Volume::intersects(const Sphere &sphere) const
{
const Vector &center = sphere.getCenter();
const real radius = sphere.getRadius();
for (int i = 0; i < m_numberOfPlanes; ++i)
if (m_plane[i].computeDistanceTo(center) > radius)
return false;
return true;
}
// ----------------------------------------------------------------------
/**
* See if the volume intersects the segment.
*
* The segment is considered to be in the volume if both points test on the negative side of any plane
*
* @param start Start point of segment.
* @param end End point of segment.
* @return False if any segment is on the negative side of any plane
*/
bool Volume::intersects(Vector const & start, Vector const & end) const
{
for (int i = 0; i < m_numberOfPlanes; ++i)
{
Plane const & plane = m_plane[i];
if (plane.computeDistanceTo(start) < 0.f && plane.computeDistanceTo(end) < 0.f)
return false;
}
return true;
}
// ----------------------------------------------------------------------
/**
* Fast Conservative check of a point cloud against the volume
*
* This routine will return true if the point could is completely outside any one
* plane of the volume. If the routine returns true, the point cloud is definitely
* outside the volume. However, a false result does not guarentee that the point
* cloud intersects the volume.
*
* @param pointCloud Point cloud to test.
* @param numberOfPoints Number of points in the point cloud.
* @return See remarks for more information.
*/
bool Volume::fastConservativeExcludes(const Vector *pointCloud, int numberOfPoints) const
{
NOT_NULL(pointCloud);
DEBUG_FATAL(numberOfPoints <= 0, ("numberOfPoints is less than 1"));
// check plane by plane
for (int i = 0; i < m_numberOfPlanes; ++i)
{
bool outside = true;
for (int j = 0; outside && j < numberOfPoints; ++j)
outside = m_plane[i].computeDistanceTo(pointCloud[j]) > 0;
if (outside)
return true;
}
return false;
}
// ----------------------------------------------------------------------
/**
* Transform the volume by the specified transformation.
*
* @param transform The transform to be applied.
*/
void Volume::transform(const Transform &newTransform)
{
for (int i = 0; i < m_numberOfPlanes; ++i)
m_plane[i].transform(newTransform);
}
// ----------------------------------------------------------------------
/**
* Transform the specified volume by the specified transformation.
*
* @param source The source volume to transform.
* @param transform The transform to be applied.
*/
void Volume::transform(const Volume &source, const Transform &newTransform)
{
if (m_numberOfPlanes != source.m_numberOfPlanes)
{
delete [] m_plane;
m_numberOfPlanes = source.m_numberOfPlanes;
m_plane = new Plane[ static_cast<uint>(m_numberOfPlanes) ];
}
for (int i = 0; i < m_numberOfPlanes; ++i)
m_plane[i].set(source.m_plane[i], newTransform);
}
// ======================================================================
@@ -0,0 +1,68 @@
// ======================================================================
//
// Volume.h
// copyright 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef VOLUME_H
#define VOLUME_H
// ======================================================================
class Plane;
class Sphere;
class Transform;
class Vector;
// ======================================================================
class Volume
{
public:
explicit Volume(int numberOfPlanes);
Volume(const Vector &originPoint, int numberOfVertices, const Vector *vertexList);
Volume (const Volume &rhs, const Transform &transform);
~Volume();
int getNumberOfPlanes() const;
void setPlane(int index, const Plane &plane);
const Plane &getPlane(int index) const;
bool contains(const Vector &point) const;
bool contains(const Sphere &sphere) const;
bool contains(const Vector *pointCloud, int numberOfPoints) const;
bool intersects(const Sphere &sphere) const;
bool intersects(Vector const & start, Vector const & end) const;
bool fastConservativeExcludes(const Vector *pointCloud, int numberOfPoints) const;
void transform(const Transform &transform);
void transform(const Volume &source, const Transform &transform);
private:
// disabled
Volume(const Volume &);
Volume &operator =(const Volume &);
private:
int m_numberOfPlanes;
Plane *m_plane;
};
// ======================================================================
// Get the number of planes in the volume
//
// @return The number of planes in the volume.
inline int Volume::getNumberOfPlanes() const
{
return m_numberOfPlanes;
}
// ======================================================================
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,218 @@
// ============================================================================
//
// WaveForm.h
// Copyright Sony Online Entertainment
//
// ============================================================================
#ifndef INCLUDED_WaveForm_H
#define INCLUDED_WaveForm_H
#include <list>
#include <string>
class WaveForm;
class WaveFormControlPointIter; // Defined below
class WaveFormEdit;
class Iff;
//-----------------------------------------------------------------------------
class WaveFormControlPoint
{
friend class WaveForm;
public:
WaveFormControlPoint();
WaveFormControlPoint(float const percent, float const value, float const randomMax = 0.0f, float const randomMin = 0.0f);
void setValue(float const value);
void setRandomMin(float const randomMin);
void setRandomMax(float const randomMax);
float getPercent() const;
float getValue() const;
float getRandomMin() const;
float getRandomMax() const;
private:
float m_percent; // [0..1]
float m_value; // [-n..n]
float m_randomMax; // [0..n]
float m_randomMin; // [0..n]
static float const m_theValueMax;
static float const m_theValueMin;
};
//-----------------------------------------------------------------------------
class WaveForm
{
public:
typedef std::list<WaveFormControlPoint> ControlPointList;
enum InterpolationType
{
IT_linear,
IT_spline,
};
enum SampleType
{
ST_initial,
ST_continuous,
};
#ifdef _DEBUG
static int getSingleValueHit();
static int getSingleValueMiss();
static int getSplineCalculationCount();
static int getLinearCalculationCount();
#endif // _DEBUG
public:
WaveForm();
WaveForm(WaveForm const &rhs);
~WaveForm();
WaveForm & operator =(WaveForm const &rhs);
#ifdef _DEBUG
// Set/get the name
std::string const &getName() const;
void setName(std::string const &name);
#endif // _DEBUG
// Get the interpolated value
float getValue(WaveFormControlPointIter &iter, float const percent) const;
// Set/Get the max and min values
void setValueMax(float const max);
void setValueMin(float const min);
float const getValueMax() const;
float const getValueMin() const;
// Copies all the data except the min and max, so the inserted data is clamped
// to the current min and max
void copyControlPoints(WaveForm const &waveForm);
// Calculates the min and max control point value
void calculateMinMax(float &max, float &min);
// Adds the control point into the correct place in the list based on the percent
void insert(WaveFormControlPoint const &controlPoint);
// Remove a control point from the waveform
void remove(ControlPointList::iterator &iter);
// Changes the values of the control point at the iterator
void setControlPoint(ControlPointList::const_iterator const &iter, WaveFormControlPoint const &controlPoint);
// Scales all the control points by the specified percent
void scaleAll(float const percent);
// Change the interpolation type
void setInterpolationType(InterpolationType const interpolationType);
// Change the sample type
void setSampleType(SampleType const sampleType);
// Remove all the control points
void clear();
// Set some random values at a random number of control points
void randomize(float const maxValue = 1.0f, float const minValue = 0.0f);
// Load the waveform from an iff
void load(Iff &iff);
// Write the waveform to an iff
void write(Iff &iff) const;
// Get the begin and end iterator from the control point list
ControlPointList::iterator getIteratorBegin();
ControlPointList::iterator getIteratorEnd();
ControlPointList::const_iterator getIteratorBegin() const;
ControlPointList::const_iterator getIteratorEnd() const;
// Get the number of control points in the list
int getControlPointCount() const;
// Get the interpolation type
InterpolationType getInterpolationType() const;
// Get the sample type
SampleType getSampleType() const;
void clampAll(float const min, float const max);
bool isConstantValue(float const val);
private:
ControlPointList m_controlPointList;
InterpolationType m_interpolationType;
SampleType m_sampleType;
float m_valueMax;
float m_valueMin;
bool m_singleValue;
// Assures the value is between the maxValue and the minValue
void clampValue(WaveFormControlPoint &controlPoint) const;
// Assures the percent value of the control point is valid, relative to
// the neighboring control points
void clampPercent(ControlPointList::iterator const &iter);
void load_0000(Iff &iff);
void load_0001(Iff &iff);
void load_0002(Iff & iff);
#ifdef _DEBUG
std::string m_name;
int m_controlPointCount;
// Verifies the iterator belongs to this waveform
bool verifyIteratorValid(ControlPointList::const_iterator const &iter) const;
#endif // _DEBUG
};
//-----------------------------------------------------------------------------
class WaveFormControlPointIter
{
public:
WaveFormControlPointIter();
void reset(WaveForm::ControlPointList::const_iterator const &iter);
WaveForm::ControlPointList::const_iterator m_iter;
float m_initialPercent; // [0..1]
};
// ============================================================================
#endif // INCLUDED_WaveForm_H
@@ -0,0 +1,71 @@
// ============================================================================
//
// WaveForm3D.cpp
// Copyright Sony Online Entertainment
//
// ============================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/WaveForm3D.h"
//-----------------------------------------------------------------------------
WaveForm3D::WaveForm3D()
: m_xWaveForm(WaveForm())
, m_yWaveForm(WaveForm())
, m_zWaveForm(WaveForm())
, m_xWaveIterator(WaveFormControlPointIter())
, m_yWaveIterator(WaveFormControlPointIter())
, m_zWaveIterator(WaveFormControlPointIter())
, m_isDirty(true)
{
}
//-----------------------------------------------------------------------------
WaveForm3D::~WaveForm3D()
{
}
//-----------------------------------------------------------------------------
void WaveForm3D::insert(float const time, Vector const & controlPoint)
{
VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(0.0f, time, 1.0f);
m_xWaveForm.insert(WaveFormControlPoint(time, controlPoint.x));
m_yWaveForm.insert(WaveFormControlPoint(time, controlPoint.y));
m_zWaveForm.insert(WaveFormControlPoint(time, controlPoint.z));
m_isDirty = true;
}
//-----------------------------------------------------------------------------
/**
* Get the value at a paricular point in time
* @param time the time
* @param point (output) the point
* @param randomOrder Set this to true if this function will be called with
* values for "time" that are not in increasing order
*/
void WaveForm3D::getValue(float const time, Vector & point, bool randomOrder)
{
VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(0.0f, time, 1.0f);
if (m_isDirty || randomOrder)
{
m_xWaveIterator.reset(m_xWaveForm.getIteratorBegin());
m_yWaveIterator.reset(m_yWaveForm.getIteratorBegin());
m_zWaveIterator.reset(m_zWaveForm.getIteratorBegin());
m_isDirty = false;
}
float const x = m_xWaveForm.getValue(m_xWaveIterator, time);
float const y = m_yWaveForm.getValue(m_yWaveIterator, time);
float const z = m_zWaveForm.getValue(m_zWaveIterator, time);
point.set(x, y, z);
}
// ============================================================================
@@ -0,0 +1,67 @@
// ============================================================================
//
// WaveForm3D.h
// Copyright Sony Online Entertainment
//
// ============================================================================
#ifndef INCLUDED_WaveForm3D_H
#define INCLUDED_WaveForm3D_H
//-------------------------------------------------------------------
#include "sharedMath/WaveForm.h"
#include "sharedMath/Vector.h"
//-------------------------------------------------------------------
//
// Simple wrapper class to the WaveForm class to manage points in 3D space
//
// Usage:
//
// WaveForm3D waveForm;
//
// // Initialize the data that the waveform can work with
//
// waveForm.insert(0.0f, Vector(0.0f, 0.0f, 0.0f)); // time must be [0.0f .. 1.0f]
// waveForm.insert(0.25f, Vector(0.0f, 0.0f, 5.0f));
// waveForm.insert(0.5f, Vector(0.0f, 0.0f, 10.0f));
// waveForm.insert(0.75f, Vector(0.0f, 0.0f, 15.0f));
// waveForm.insert(1.0f, Vector(0.0f, 0.0f, 20.0f));
//
// .
// .
// .
//
// // at a later time extract the interpolated result
//
// float const time = 0.2358f; //must be [0.0f .. 1.0f]
// Vector pointAtTime;
//
// waveForm.getValue(time, pointAtTime);
//
//-------------------------------------------------------------------
class WaveForm3D
{
public:
WaveForm3D();
~WaveForm3D();
void insert(float const time, Vector const & controlPoint);
void getValue(float const time, Vector & point, bool randomOrder = false);
private:
WaveForm m_xWaveForm;
WaveForm m_yWaveForm;
WaveForm m_zWaveForm;
WaveFormControlPointIter m_xWaveIterator;
WaveFormControlPointIter m_yWaveIterator;
WaveFormControlPointIter m_zWaveIterator;
bool m_isDirty;
};
#endif
@@ -0,0 +1,174 @@
// ======================================================================
//
// AxialBox.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/AxialBox.h"
#include "sharedMath/Range.h"
#include <algorithm> // for min/max
#include <vector> // for min/max
// ======================================================================
AxialBox::AxialBox() :
m_min( Vector::maxXYZ ),
m_max( Vector::negativeMaxXYZ )
{
}
AxialBox::AxialBox ( Vector const & cornerA, Vector const & cornerB )
{
if (cornerA.x < cornerB.x)
{
m_min.x = cornerA.x;
m_max.x = cornerB.x;
}
else
{
m_min.x = cornerB.x;
m_max.x = cornerA.x;
}
if (cornerA.y < cornerB.y)
{
m_min.y = cornerA.y;
m_max.y = cornerB.y;
}
else
{
m_min.y = cornerB.y;
m_max.y = cornerA.y;
}
if (cornerA.z < cornerB.z)
{
m_min.z = cornerA.z;
m_max.z = cornerB.z;
}
else
{
m_min.z = cornerB.z;
m_max.z = cornerA.z;
}
}
AxialBox::AxialBox( Range const & rX, Range const & rY, Range const & rZ )
: m_min(rX.getMin(),rY.getMin(),rZ.getMin()),
m_max(rX.getMax(),rY.getMax(),rZ.getMax())
{
}
AxialBox::AxialBox( AxialBox const & boxA, AxialBox const & boxB )
: m_min( boxA.getMin() ),
m_max( boxA.getMax() )
{
add(boxB);
}
// ----------------------------------------------------------------------
void AxialBox::clear ( void )
{
m_min = Vector::maxXYZ;
m_max = Vector::negativeMaxXYZ;
}
void AxialBox::add ( Vector const & V )
{
if (m_min.x > m_max.x)
{
addMin(V);
addMax(V);
}
else
{
if (V.x < m_min.x)
m_min.x = V.x;
else if (V.x > m_max.x)
m_max.x = V.x;
if (V.y < m_min.y)
m_min.y = V.y;
else if (V.y > m_max.y)
m_max.y = V.y;
if (V.z < m_min.z)
m_min.z = V.z;
else if (V.z > m_max.z)
m_max.z = V.z;
}
}
void AxialBox::addMin ( Vector const & V )
{
if (V.x < m_min.x)
m_min.x = V.x;
if (V.y < m_min.y)
m_min.y = V.y;
if (V.z < m_min.z)
m_min.z = V.z;
}
void AxialBox::addMax ( Vector const & V )
{
if (V.x > m_max.x)
m_max.x = V.x;
if (V.y > m_max.y)
m_max.y = V.y;
if (V.z > m_max.z)
m_max.z = V.z;
}
void AxialBox::add ( std::vector<Vector> const & vertices )
{
VertexList::const_iterator const iEnd = vertices.end();
for (VertexList::const_iterator i = vertices.begin(); i != iEnd; ++i)
add(*i);
}
void AxialBox::add ( AxialBox const & A )
{
addMin(A.getMin());
addMax(A.getMax());
}
bool AxialBox::contains ( Vector const & V ) const
{
if( V.z < m_min.z ) return false;
if( V.x < m_min.x ) return false;
if( V.y < m_min.y ) return false;
if( V.z > m_max.z ) return false;
if( V.x > m_max.x ) return false;
if( V.y > m_max.y ) return false;
return true;
}
bool AxialBox::contains ( AxialBox const & A ) const
{
return contains ( A.m_min ) && contains ( A.m_max );
}
bool AxialBox::isEmpty ( void ) const
{
// All should be valid if we have initialized it at all.
return m_min.x > m_max.x;
}
Range AxialBox::getRangeX ( void ) const { return Range(m_min.x,m_max.x); }
Range AxialBox::getRangeY ( void ) const { return Range(m_min.y,m_max.y); }
Range AxialBox::getRangeZ ( void ) const { return Range(m_min.z,m_max.z); }
bool AxialBox::intersects (const AxialBox& other) const
{
return !(m_max.x < other.m_min.x || m_min.x > other.m_max.x || m_max.y < other.m_min.y || m_min.y > other.m_max.y || m_max.z < other.m_min.z || m_min.z > other.m_max.z);
}
@@ -0,0 +1,180 @@
// ======================================================================
//
// AxialBox.h
// copyright (c) 2001 Sony Online Entertainment
//
// ----------------------------------------------------------------------
#ifndef INCLUDED_AxialBox_H
#define INCLUDED_AxialBox_H
#include "sharedMath/Vector.h"
class Range;
// ======================================================================
class AxialBox
{
public:
typedef stdvector<Vector>::fwd VertexList;
public:
AxialBox();
AxialBox( Vector const & cornerA, Vector const & cornerB );
AxialBox( Range const & rX, Range const & rY, Range const & rZ );
AxialBox( AxialBox const & boxA, AxialBox const & boxB );
void clear ( void );
void add ( Vector const & V );
void addMin ( Vector const & V );
void addMax ( Vector const & V );
void add ( VertexList const & vertices );
void add ( AxialBox const & A );
bool contains ( Vector const & V ) const;
bool contains ( AxialBox const & A ) const;
bool isEmpty ( void ) const;
// ----------
Vector const & getMin ( void ) const;
Vector const & getMax ( void ) const;
void setMin ( Vector const & newMin );
void setMax ( Vector const & newMax );
real getWidth ( void ) const;
real getHeight ( void ) const;
real getDepth ( void ) const;
Vector getSize ( void ) const;
Vector getCenter ( void ) const;
Vector getDelta ( void ) const;
real getRadius ( void ) const;
float getRadiusSquared() const;
Range getRangeX ( void ) const;
Range getRangeY ( void ) const;
Range getRangeZ ( void ) const;
Vector getBase ( void ) const;
Vector getCorner ( int whichCorner ) const;
real getVolume ( void ) const;
real getArea ( void ) const;
// ----------
Vector const & getAxisX ( void ) const;
Vector const & getAxisY ( void ) const;
Vector const & getAxisZ ( void ) const;
float getExtentX ( void ) const;
float getExtentY ( void ) const;
float getExtentZ ( void ) const;
bool intersects ( AxialBox const & other ) const;
protected:
Vector m_min;
Vector m_max;
};
// ----------------------------------------------------------------------
inline Vector const & AxialBox::getMin ( void ) const { return m_min; }
inline Vector const & AxialBox::getMax ( void ) const { return m_max; }
inline void AxialBox::setMin ( Vector const & newMin ) { m_min = newMin; }
inline void AxialBox::setMax ( Vector const & newMax ) { m_max = newMax; }
inline real AxialBox::getWidth ( void ) const { return m_max.x - m_min.x; }
inline real AxialBox::getHeight ( void ) const { return m_max.y - m_min.y; }
inline real AxialBox::getDepth ( void ) const { return m_max.z - m_min.z; }
inline Vector AxialBox::getSize ( void ) const { return (m_max - m_min); }
inline Vector AxialBox::getCenter ( void ) const { return (m_max + m_min) / 2.0f; }
inline Vector AxialBox::getDelta ( void ) const { return (m_max - m_min) / 2.0f; }
inline real AxialBox::getRadius ( void ) const { return getDelta().magnitude(); }
inline float AxialBox::getRadiusSquared() const
{
return getDelta().magnitudeSquared();
}
inline Vector AxialBox::getBase ( void ) const { return Vector( (m_min.x + m_max.x) / 2.0f, m_min.y, (m_min.z + m_max.z) / 2.0f ); }
inline Vector AxialBox::getCorner ( int whichCorner ) const
{
// These corners are ordered so that the first 4 are on the bottom of the box
switch(whichCorner)
{
case 0: return Vector( m_min.x, m_min.y, m_min.z );
case 1: return Vector( m_max.x, m_min.y, m_min.z );
case 2: return Vector( m_min.x, m_min.y, m_max.z );
case 3: return Vector( m_max.x, m_min.y, m_max.z );
case 4: return Vector( m_min.x, m_max.y, m_min.z );
case 5: return Vector( m_max.x, m_max.y, m_min.z );
case 6: return Vector( m_min.x, m_max.y, m_max.z );
case 7: return Vector( m_max.x, m_max.y, m_max.z );
default: return Vector(0,0,0);
}
}
inline float AxialBox::getVolume ( void ) const
{
return (m_max.x - m_min.x) * (m_max.y - m_min.y) * (m_max.z - m_min.z);
}
inline float AxialBox::getArea ( void ) const
{
Vector V = getSize();
return ((V.x * V.y) + (V.y * V.z) + (V.z * V.x)) * 2.0f;
}
// ----------------------------------------------------------------------
inline Vector const & AxialBox::getAxisX ( void ) const
{
return Vector::unitX;
}
inline Vector const & AxialBox::getAxisY ( void ) const
{
return Vector::unitY;
}
inline Vector const & AxialBox::getAxisZ ( void ) const
{
return Vector::unitZ;
}
// ----------
inline float AxialBox::getExtentX ( void ) const
{
return (m_max.x - m_min.x) / 2.0f;
}
inline float AxialBox::getExtentY ( void ) const
{
return (m_max.y - m_min.y) / 2.0f;
}
inline float AxialBox::getExtentZ ( void ) const
{
return (m_max.z - m_min.z) / 2.0f;
}
// ----------------------------------------------------------------------
#endif
@@ -0,0 +1,11 @@
// ======================================================================
//
// Capsule.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Capsule.h"
@@ -0,0 +1,174 @@
// ======================================================================
//
// Capsule.h
// copyright (c) 2001 Sony Online Entertainment
//
// ----------------------------------------------------------------------
#ifndef INCLUDED_Capsule_H
#define INCLUDED_Capsule_H
#include "sharedMath/Vector.h"
#include "sharedMath/Sphere.h"
// ----------------------------------------------------------------------
class Capsule
{
public:
Capsule ( Vector const & A, Vector const & B, float radius );
Capsule ( Sphere const & A, Vector const & delta );
Vector const & getPointA ( void ) const;
Vector const & getPointB ( void ) const;
float const & getRadius ( void ) const;
// ----------
Vector getCenter ( void ) const;
float getTotalRadius ( void ) const;
Sphere getBoundingSphere ( void ) const;
Sphere getSphereA ( void ) const;
Sphere getSphereB ( void ) const;
Vector getDelta ( void ) const;
// ----------
bool contains ( Sphere const & S ) const;
bool intersectsSphere ( Sphere const & S ) const;
protected:
Vector m_pointA;
Vector m_pointB;
float m_radius;
// These two values help accelerate sphere tree queries
Vector m_normal;
float m_segmentLength;
};
// ----------
inline Capsule::Capsule ( Vector const & A, Vector const & B, float radius )
: m_pointA(A), m_pointB(B), m_radius(radius)
{
Vector delta = B - A;
m_segmentLength = delta.magnitude();
if(m_segmentLength > 0.0f)
{
m_normal = delta / m_segmentLength;
}
else
{
m_normal = Vector::zero;
}
}
inline Capsule::Capsule ( Sphere const & S, Vector const & delta )
: m_pointA(S.getCenter()),
m_pointB(S.getCenter() + delta),
m_radius(S.getRadius())
{
m_segmentLength = delta.magnitude();
if(m_segmentLength > 0.0f)
{
m_normal = delta / m_segmentLength;
}
else
{
m_normal = Vector::zero;
}
}
inline Vector const & Capsule::getPointA ( void ) const
{
return m_pointA;
}
inline Vector const & Capsule::getPointB ( void ) const
{
return m_pointB;
}
inline float const & Capsule::getRadius ( void ) const
{
return m_radius;
}
inline Vector Capsule::getCenter ( void ) const
{
return (m_pointA + m_pointB) / 2.0f;
}
inline float Capsule::getTotalRadius ( void ) const
{
return m_radius + (m_segmentLength / 2.0f);
}
inline Sphere Capsule::getBoundingSphere ( void ) const
{
return Sphere(getCenter(),getTotalRadius());
}
// ----------
inline Sphere Capsule::getSphereA ( void ) const
{
return Sphere(m_pointA,m_radius);
}
inline Sphere Capsule::getSphereB ( void ) const
{
return Sphere(m_pointB,m_radius);
}
inline Vector Capsule::getDelta ( void ) const
{
return m_pointB - m_pointA;
}
// ----------------------------------------------------------------------
inline bool Capsule::contains ( Sphere const & S ) const
{
if(m_radius < S.getRadius()) return false;
Vector D = S.getCenter() - m_pointA;
float t = clamp(0.0f, D.dot(m_normal), m_segmentLength);
float diff2 = sqr(m_radius - S.getRadius());
float dist2 = D.magnitudeBetweenSquared(m_normal * t);
return dist2 < diff2;
}
inline bool Capsule::intersectsSphere ( Sphere const & S ) const
{
Vector D = S.getCenter() - m_pointA;
float t = clamp(0.0f, D.dot(m_normal), m_segmentLength);
float sum2 = sqr(m_radius + S.getRadius());
float dist2 = D.magnitudeBetweenSquared(m_normal * t);
return dist2 < sum2;
}
// ----------------------------------------------------------------------
#endif // #ifndef INCLUDED_Capsule_H
@@ -0,0 +1,34 @@
// ======================================================================
//
// Circle.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Circle.h"
#include "sharedMath/Plane3d.h"
#include "sharedMath/Range.h"
Range Circle::getRangeX ( void ) const
{
return Range( m_center.x - m_radius, m_center.x + m_radius );
}
Range Circle::getRangeZ ( void ) const
{
return Range( m_center.z - m_radius, m_center.z + m_radius );
}
Range Circle::getLocalRangeX ( void ) const
{
return Range( -m_radius, m_radius );
}
Plane3d Circle::getPlane ( void ) const
{
return Plane3d(m_center,Vector::unitY);
}
@@ -0,0 +1,92 @@
// ======================================================================
//
// Circle.h
// copyright (c) 2001 Sony Online Entertainment
//
// Simple class to represent a 2D circle in the X-Z plane
//
// ----------------------------------------------------------------------
#ifndef INCLUDED_Circle_H
#define INCLUDED_Circle_H
#include "sharedMath/Vector.h"
class Range;
class Plane3d;
// ======================================================================
class Circle
{
public:
Circle ( Vector const & center, float radius );
// ----------
Vector const & getCenter ( void ) const;
void setCenter ( Vector const & center );
float getRadius ( void ) const;
void setRadius ( float radius );
float getRadiusSquared ( void ) const;
Range getRangeX ( void ) const;
Range getRangeZ ( void ) const;
Range getLocalRangeX ( void ) const;
Plane3d getPlane ( void ) const;
protected:
Vector m_center;
float m_radius;
};
// ----------------------------------------------------------------------
inline Circle::Circle ( Vector const & center, float radius )
: m_center(center),
m_radius(radius)
{
}
// ----------
inline Vector const & Circle::getCenter ( void ) const
{
return m_center;
}
inline void Circle::setCenter ( Vector const & center )
{
m_center = center;
}
// ----------
inline float Circle::getRadius ( void ) const
{
return m_radius;
}
inline void Circle::setRadius ( float radius )
{
m_radius = radius;
}
// ----------
inline float Circle::getRadiusSquared ( void ) const
{
return m_radius * m_radius;
}
// ----------------------------------------------------------------------
#endif
@@ -0,0 +1,39 @@
// ======================================================================
//
// Cylinder.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Cylinder.h"
#include "sharedMath/Circle.h"
#include "sharedMath/Range.h"
#include "sharedMath/Ring.h"
Ring Cylinder::getTopRing ( void ) const
{
return Ring( Vector(m_base.x, m_base.y + m_height, m_base.z), m_radius );
}
Ring Cylinder::getBaseRing ( void ) const
{
return Ring( m_base, m_radius );
}
Range Cylinder::getRangeY ( void ) const
{
return Range( m_base.y, m_base.y + m_height );
}
Circle Cylinder::getTopCircle ( void ) const
{
return Circle( Vector(m_base.x, m_base.y + m_height, m_base.z), m_radius );
}
Circle Cylinder::getBaseCircle ( void ) const
{
return Circle( m_base, m_radius );
}
@@ -0,0 +1,160 @@
// ======================================================================
//
// Cylinder.h
// copyright (c) 2001 Sony Online Entertainment
//
// Very, very simple Y-axis aligned cylinder used for simple collision
//
// ----------------------------------------------------------------------
#ifndef INCLUDED_Cylinder_H
#define INCLUDED_Cylinder_H
#include "sharedMath/Vector.h"
class Range;
class Circle;
class Ring;
// ======================================================================
class Cylinder
{
public:
Cylinder();
Cylinder( Vector const & base, real radius, real height );
Vector const & getBase ( void ) const;
float getRadius ( void ) const;
float getHeight ( void ) const;
void setBase ( Vector const & newBase );
void setRadius ( real newRadius );
void setHeight ( real newHeight );
// ----------
// Helper methods for MultiShape
Vector getCenter ( void ) const;
Vector const & getAxisX ( void ) const;
Vector const & getAxisY ( void ) const;
Vector const & getAxisZ ( void ) const;
float getExtentX ( void ) const;
float getExtentY ( void ) const;
float getExtentZ ( void ) const;
// ----------
Range getRangeY ( void ) const;
Circle getTopCircle ( void ) const;
Circle getBaseCircle ( void ) const;
Ring getTopRing ( void ) const;
Ring getBaseRing ( void ) const;
protected:
Vector m_base;
float m_radius;
float m_height;
};
// ----------------------------------------------------------------------
inline Cylinder::Cylinder()
: m_base( Vector::zero ),
m_radius( 1.0f ),
m_height( 1.0f )
{
}
inline Cylinder::Cylinder ( Vector const & base, real radius, real height )
: m_base(base),
m_radius(radius),
m_height(height)
{
}
// ----------------------------------------------------------------------
inline Vector const & Cylinder::getBase ( void ) const
{
return m_base;
}
inline float Cylinder::getRadius ( void ) const
{
return m_radius;
}
inline float Cylinder::getHeight ( void ) const
{
return m_height;
}
// ----------------------------------------------------------------------
inline void Cylinder::setBase ( Vector const & newBase )
{
m_base = newBase;
}
inline void Cylinder::setRadius ( real newRadius )
{
m_radius = newRadius;
}
inline void Cylinder::setHeight ( real newHeight )
{
m_height = newHeight;
}
// ----------------------------------------------------------------------
inline Vector Cylinder::getCenter ( void ) const
{
return m_base + Vector( 0.0f, m_height / 2.0f, 0.0f );
}
// ----------
inline Vector const & Cylinder::getAxisX ( void ) const
{
return Vector::unitX;
}
inline Vector const & Cylinder::getAxisY ( void ) const
{
return Vector::unitY;
}
inline Vector const & Cylinder::getAxisZ ( void ) const
{
return Vector::unitZ;
}
// ----------
inline float Cylinder::getExtentX ( void ) const
{
return getRadius();
}
inline float Cylinder::getExtentY ( void ) const
{
return getHeight() / 2.0f;
}
inline float Cylinder::getExtentZ ( void ) const
{
return getRadius();
}
// ----------------------------------------------------------------------
#endif // #ifdef INCLUDED_Cylinder_H
@@ -0,0 +1,80 @@
// ======================================================================
//
// Hsv.cpp
// copyright 2005 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Hsv.h"
#include "sharedMath/Vector.h"
#include "sharedMath/VectorArgb.h"
#include "sharedMath/VectorRgba.h"
#include <algorithm>
// ======================================================================
void Hsv::rgbToHsv(float const red, float const green, float const blue, float &hue, float &saturation, float &value)
{
float const min = std::min(red, std::min(green, blue));
float const max = std::max(red, std::max(green, blue));
float const delta = (max - min);
hue = 0.0f;
saturation = 0.0f;
value = max;
if (max > 0.0f)
{
saturation = delta / max;
}
else
{
hue = -1.0f;
return;
}
if (delta > 0.0f)
{
if (WithinEpsilonInclusive(red, max, 0.0001f))
{
hue = (green - blue) / delta; // between yellow and magenta
}
else if (WithinEpsilonInclusive(green, max, 0.0001f))
{
hue = 2.0f + (blue - red) / delta; // between cyan and yellow
}
else
{
hue = 4.0f + (red - green) / delta; // between magenta and cyan
}
}
hue *= 60.0f; // degrees
if (hue < 0.0f)
{
hue += 360.0f;
}
}
// ----------------------------------------------------------------------
void Hsv::rgbToHsv(VectorArgb const & rgb, Vector & hsv )
{
rgbToHsv(rgb.r, rgb.g, rgb.b, hsv.x, hsv.y, hsv.z);
}
// ----------------------------------------------------------------------
void Hsv::rgbToHsv(VectorRgba const & rgb, Vector & hsv )
{
rgbToHsv(rgb.r, rgb.g, rgb.b, hsv.x, hsv.y, hsv.z);
}
//===================================================================
@@ -0,0 +1,33 @@
//===================================================================
//
// Hsv.h
// copyright 2005 Sony Online Entertainment
//
//===================================================================
#ifndef INCLUDED_Hsv_H
#define INCLUDED_Hsv_H
//===================================================================
class Vector;
class VectorArgb;
class VectorRgba;
//===================================================================
class Hsv
{
public:
static void rgbToHsv(float const red, float const green, float const blue, float &hue, float &saturation, float &value);
static void rgbToHsv(VectorArgb const & rgb, Vector & hsv );
static void rgbToHsv(VectorRgba const & rgb, Vector & hsv );
};
//===================================================================
#endif
@@ -0,0 +1,9 @@
// ======================================================================
//
// Line3d.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
//#include "sharedMath/Line3d.h"
@@ -0,0 +1,70 @@
// ======================================================================
//
// Line3d.h
// copyright (c) 2001 Sony Online Entertainment
//
// ----------------------------------------------------------------------
#ifndef INCLUDED_Line3d_H
#define INCLUDED_Line3d_H
#include "sharedMath/Vector.h"
// ----------------------------------------------------------------------
class Line3d
{
public:
Line3d ( Vector const & p, Vector const & d );
Vector const & getPoint ( void ) const;
Vector const & getNormal ( void ) const;
Vector atParam ( float t ) const;
void flip ( void );
Line3d flipped ( void ) const;
protected:
Vector m_point;
Vector m_normal;
};
// ----------
inline Line3d::Line3d ( Vector const & p, Vector const & d )
: m_point(p),
m_normal(d)
{
}
inline Vector const & Line3d::getPoint ( void ) const
{
return m_point;
}
inline Vector const & Line3d::getNormal ( void ) const
{
return m_normal;
}
inline Vector Line3d::atParam ( float t ) const
{
return m_point + m_normal * t;
}
inline void Line3d::flip ( void )
{
m_normal = -m_normal;
}
inline Line3d Line3d::flipped ( void ) const
{
return Line3d(m_point,-m_normal);
}
// ----------------------------------------------------------------------
#endif // #ifdef INCLUDED_Line3d_H
@@ -0,0 +1,414 @@
// ======================================================================
//
// MultiShape.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/MultiShape.h"
#include "sharedMath/Transform.h"
#include "sharedMath/Sphere.h"
#include "sharedMath/Cylinder.h"
#include "sharedMath/OrientedCylinder.h"
#include "sharedMath/AxialBox.h"
#include "sharedMath/YawedBox.h"
#include "sharedMath/OrientedBox.h"
#include <algorithm> // for max
MultiShape::ShapeType shapeTable[MultiShape::MSBT_Count][MultiShape::MSOT_Count] =
{
{ MultiShape::MST_Sphere, MultiShape::MST_Sphere, MultiShape::MST_Sphere },
{ MultiShape::MST_Cylinder, MultiShape::MST_Cylinder, MultiShape::MST_OrientedCylinder },
{ MultiShape::MST_AxialBox, MultiShape::MST_YawedBox, MultiShape::MST_OrientedBox }
};
// ----------------------------------------------------------------------
MultiShape::MultiShape()
: m_baseType ( MSBT_Invalid ),
m_shapeType( MST_Invalid ),
m_center( Vector::zero ),
m_axisX( Vector::unitX ),
m_axisY( Vector::unitY ),
m_axisZ( Vector::unitZ ),
m_extentX( 1.0f ),
m_extentY( 1.0f ),
m_extentZ( 1.0f )
{
}
// ----------
MultiShape::MultiShape ( BaseType baseType,
ShapeType shapeType,
Vector const & center,
Vector const & axisX,
Vector const & axisY,
Vector const & axisZ,
float extentX,
float extentY,
float extentZ )
: m_baseType(baseType),
m_shapeType(shapeType),
m_center(center),
m_axisX(axisX),
m_axisY(axisY),
m_axisZ(axisZ),
m_extentX(extentX),
m_extentY(extentY),
m_extentZ(extentZ)
{
}
// ----------
MultiShape::MultiShape ( BaseType baseType,
Vector const & center,
Vector const & axisX,
Vector const & axisY,
Vector const & axisZ,
float extentX,
float extentY,
float extentZ )
: m_baseType(baseType),
m_shapeType(MST_Invalid),
m_center(center),
m_axisX(axisX),
m_axisY(axisY),
m_axisZ(axisZ),
m_extentX(extentX),
m_extentY(extentY),
m_extentZ(extentZ)
{
updateShapeType();
}
// ----------
MultiShape::MultiShape ( Sphere const & shape )
: m_baseType ( MSBT_Sphere ),
m_shapeType ( MST_Sphere ),
m_center ( shape.getCenter() ),
m_axisX ( shape.getAxisX() ),
m_axisY ( shape.getAxisY() ),
m_axisZ ( shape.getAxisZ() ),
m_extentX ( shape.getExtentX() ),
m_extentY ( shape.getExtentY() ),
m_extentZ ( shape.getExtentZ() )
{
}
// ----------
MultiShape::MultiShape ( Cylinder const & shape )
: m_baseType ( MSBT_Cylinder ),
m_shapeType ( MST_Cylinder ),
m_center ( shape.getCenter() ),
m_axisX ( shape.getAxisX() ),
m_axisY ( shape.getAxisY() ),
m_axisZ ( shape.getAxisZ() ),
m_extentX ( shape.getExtentX() ),
m_extentY ( shape.getExtentY() ),
m_extentZ ( shape.getExtentZ() )
{
}
// ----------
MultiShape::MultiShape ( OrientedCylinder const & shape )
: m_baseType ( MSBT_Cylinder ),
m_shapeType ( MST_OrientedCylinder ),
m_center ( shape.getCenter() ),
m_axisX ( shape.getAxisX() ),
m_axisY ( shape.getAxisY() ),
m_axisZ ( shape.getAxisZ() ),
m_extentX ( shape.getExtentX() ),
m_extentY ( shape.getExtentY() ),
m_extentZ ( shape.getExtentZ() )
{
}
// ----------
MultiShape::MultiShape ( AxialBox const & shape )
: m_baseType ( MSBT_Box ),
m_shapeType ( MST_AxialBox ),
m_center ( shape.getCenter() ),
m_axisX ( shape.getAxisX() ),
m_axisY ( shape.getAxisY() ),
m_axisZ ( shape.getAxisZ() ),
m_extentX ( shape.getExtentX() ),
m_extentY ( shape.getExtentY() ),
m_extentZ ( shape.getExtentZ() )
{
}
// ----------
MultiShape::MultiShape ( YawedBox const & shape )
: m_baseType ( MSBT_Box ),
m_shapeType ( MST_YawedBox ),
m_center ( shape.getCenter() ),
m_axisX ( shape.getAxisX() ),
m_axisY ( shape.getAxisY() ),
m_axisZ ( shape.getAxisZ() ),
m_extentX ( shape.getExtentX() ),
m_extentY ( shape.getExtentY() ),
m_extentZ ( shape.getExtentZ() )
{
}
// ----------
MultiShape::MultiShape ( OrientedBox const & shape )
: m_baseType ( MSBT_Box ),
m_shapeType ( MST_OrientedBox ),
m_center ( shape.getCenter() ),
m_axisX ( shape.getAxisX() ),
m_axisY ( shape.getAxisY() ),
m_axisZ ( shape.getAxisZ() ),
m_extentX ( shape.getExtentX() ),
m_extentY ( shape.getExtentY() ),
m_extentZ ( shape.getExtentZ() )
{
}
// ----------------------------------------------------------------------
void MultiShape::updateShapeType ( void )
{
const real axisEpsilon = 0.0000001f;
bool xOK = m_axisX.magnitudeBetweenSquared( Vector::unitX ) < axisEpsilon;
bool yOK = m_axisY.magnitudeBetweenSquared( Vector::unitY ) < axisEpsilon;
bool zOK = m_axisZ.magnitudeBetweenSquared( Vector::unitZ ) < axisEpsilon;
MultiShape::OrientType orientType = MultiShape::MSOT_Oriented;
if(xOK && yOK && zOK) orientType = MultiShape::MSOT_AxisAligned;
else if(yOK) orientType = MultiShape::MSOT_Yawed;
MultiShape::ShapeType shapeType = shapeTable[m_baseType][orientType];
m_shapeType = shapeType;
}
// ----------------------------------------------------------------------
// @todo - This really needs to go somewhere else.
// Calculate the radius of the tight-fitting axial cylinder.
float MultiShape::calcAvoidanceRadius ( void ) const
{
switch(m_shapeType)
{
case MST_Sphere:
return m_extentX;
case MST_Cylinder:
return m_extentX;
case MST_OrientedCylinder:
{
// Slightly tricky - there are two contact modes between an
// oriented cylinder and its tight-fitting axial cylinder -
// two-contact (cylinder is tilted slightly) and four-contact
// cylinder is on its side). The maximum of those two radii is
// the radius of the tight-fitting cylinder.
float sinTheta = m_axisY.y;
float cosTheta = sqrt( m_axisY.x * m_axisY.x + m_axisY.z * m_axisY.z );
float twoContactRadius = abs(m_extentY * sinTheta + m_extentX * cosTheta);
float blah = m_extentY * sinTheta;
float fourContactRadius = sqrt(m_extentX * m_extentX + blah * blah);
return std::max(twoContactRadius,fourContactRadius);
}
case MST_AxialBox:
return sqrt(m_extentX * m_extentX + m_extentZ * m_extentZ);
case MST_YawedBox:
return sqrt(m_extentX * m_extentX + m_extentZ * m_extentZ);
case MST_OrientedBox:
{
// There's gotta be a cheaper way to calculate this radius...
// Take four corners at one end of the box, figure out which
// is the farthest from the Y axis. Four is sufficient because
// of symmetry.
Vector Y = m_axisY * m_extentY;
Vector A = Y + m_axisX * m_extentX + m_axisZ * m_extentZ;
Vector B = Y + m_axisX * m_extentX - m_axisZ * m_extentZ;
Vector C = Y - m_axisX * m_extentX + m_axisZ * m_extentZ;
Vector D = Y - m_axisX * m_extentX - m_axisZ * m_extentZ;
float magA = sqrt( A.x * A.x + A.z * A.z );
float magB = sqrt( B.x * B.x + B.z * B.z );
float magC = sqrt( C.x * C.x + C.z * C.z );
float magD = sqrt( D.x * D.x + D.z * D.z );
return std::max( std::max(magA,magB), std::max(magC,magD) );
}
default:
return 0.0f;
}
}
// ----------------------------------------------------------------------
AxialBox MultiShape::getBoundingBox ( void ) const
{
switch(m_shapeType)
{
case MST_Sphere:
case MST_Cylinder:
case MST_AxialBox:
return getAxialBox();
case MST_YawedBox:
{
YawedBox box = getYawedBox();
AxialBox temp;
for(int i = 0; i < 8; i++) temp.add(box.getCorner(i));
return temp;
}
case MST_OrientedCylinder:
case MST_OrientedBox:
{
OrientedBox box = getOrientedBox();
AxialBox temp;
for(int i = 0; i < 8; i++) temp.add(box.getCorner(i));
return temp;
}
default:
DEBUG_WARNING(true,("MultiShape::getBoundingBox - Trying to get a bounding box for an unsupported type"));
return AxialBox();
}
}
// ----------
Sphere MultiShape::getBoundingSphere ( void ) const
{
float radius;
if (m_baseType == MSBT_Sphere)
{
radius = m_extentX;
}
else
{
radius = sqrt( m_extentX*m_extentX + m_extentY*m_extentY + m_extentZ*m_extentZ );
}
return Sphere( m_center, radius );
}
// ----------------------------------------------------------------------
Sphere MultiShape::getSphere ( void ) const
{
return Sphere( m_center, m_extentX );
}
// ----------
Cylinder MultiShape::getCylinder ( void ) const
{
return Cylinder( getBase(), m_extentX, getHeight() );
}
// ----------
OrientedCylinder MultiShape::getOrientedCylinder ( void ) const
{
return OrientedCylinder( getBase(), m_axisY, m_extentX, getHeight() );
}
// ----------
AxialBox MultiShape::getAxialBox ( void ) const
{
Vector min = m_center - Vector( m_extentX, m_extentY, m_extentZ );
Vector max = m_center + Vector( m_extentX, m_extentY, m_extentZ );
return AxialBox( min, max );
}
// ----------
YawedBox MultiShape::getYawedBox ( void ) const
{
return YawedBox( getBase(), m_axisX, m_axisZ, m_extentX, m_extentZ, getHeight() );
}
// ----------
OrientedBox MultiShape::getOrientedBox ( void ) const
{
return OrientedBox( m_center, m_axisX, m_axisY, m_axisZ, m_extentX, m_extentY, m_extentZ );
}
// ----------------------------------------------------------------------
Sphere MultiShape::getLocalSphere ( void ) const
{
return Sphere( Vector::zero, m_extentX );
}
// ----------
Cylinder MultiShape::getLocalCylinder ( void ) const
{
return Cylinder( Vector(0.0f,-m_extentY,0.0f), m_extentX, getHeight() );
}
// ----------
AxialBox MultiShape::getLocalAxialBox ( void ) const
{
Vector min = -Vector( m_extentX, m_extentY, m_extentZ );
Vector max = Vector( m_extentX, m_extentY, m_extentZ );
return AxialBox( min, max );
}
// ----------------------------------------------------------------------
Transform MultiShape::getTransform_l2p ( void ) const
{
Transform temp(Transform::IF_none);
temp.setLocalFrameIJK_p( m_axisX, m_axisY, m_axisZ );
temp.setPosition_p( m_center );
return temp;
}
Transform MultiShape::getTransform_p2l ( void ) const
{
Transform temp(Transform::IF_none);
temp.invert( getTransform_l2p() );
return temp;
}
// ----------------------------------------------------------------------
@@ -0,0 +1,258 @@
// ======================================================================
//
// MultiShape.h
// copyright (c) 2001 Sony Online Entertainment
//
// MultiShape is a simple class that can be used to represent a sphere,
// cylinder, or box, oriented or axial.
//
// ----------------------------------------------------------------------
#ifndef INCLUDED_MultiShape_H
#define INCLUDED_MultiShape_H
#include "sharedMath/Vector.h"
class Sphere;
class Cylinder;
class OrientedCylinder;
class AxialBox;
class YawedBox;
class OrientedBox;
class Transform;
// ======================================================================
class MultiShape
{
public:
enum BaseType
{
MSBT_Sphere,
MSBT_Cylinder,
MSBT_Box,
MSBT_Count,
MSBT_Invalid,
};
enum OrientType
{
MSOT_AxisAligned,
MSOT_Yawed,
MSOT_Oriented,
MSOT_Count,
MSOT_Invalid,
};
enum ShapeType
{
MST_Sphere,
MST_Cylinder,
MST_OrientedCylinder,
MST_AxialBox,
MST_YawedBox,
MST_OrientedBox,
MST_Count,
MST_Invalid,
};
// ----------
MultiShape();
MultiShape ( BaseType baseType,
Vector const & center,
Vector const & axisX,
Vector const & axisY,
Vector const & axisZ,
float extentX,
float extentY,
float extentZ );
MultiShape ( BaseType baseType,
ShapeType shapeType,
Vector const & center,
Vector const & axisX,
Vector const & axisY,
Vector const & axisZ,
float extentX,
float extentY,
float extentZ );
explicit MultiShape ( Sphere const & shape );
explicit MultiShape ( Cylinder const & shape );
explicit MultiShape ( OrientedCylinder const & shape );
explicit MultiShape ( AxialBox const & shape );
explicit MultiShape ( YawedBox const & shape );
explicit MultiShape ( OrientedBox const & shape );
// ----------
BaseType getBaseType ( void ) const;
ShapeType getShapeType ( void ) const;
Vector const & getCenter ( void ) const;
Vector const & getAxisX ( void ) const;
Vector const & getAxisY ( void ) const;
Vector const & getAxisZ ( void ) const;
float getExtentX ( void ) const;
float getExtentY ( void ) const;
float getExtentZ ( void ) const;
void setExtentX ( float newExtent );
void setExtentY ( float newExtent );
void setExtentZ ( float newExtent );
// ----------
Vector getBase ( void ) const;
float getWidth ( void ) const;
float getHeight ( void ) const;
float getDepth ( void ) const;
float calcAvoidanceRadius ( void ) const;
void updateShapeType ( void );
Sphere getBoundingSphere ( void ) const;
AxialBox getBoundingBox ( void ) const;
// ----------
Sphere getSphere ( void ) const;
Cylinder getCylinder ( void ) const;
OrientedCylinder getOrientedCylinder ( void ) const;
AxialBox getAxialBox ( void ) const;
YawedBox getYawedBox ( void ) const;
OrientedBox getOrientedBox ( void ) const;
// ----------
Sphere getLocalSphere ( void ) const;
Cylinder getLocalCylinder ( void ) const;
AxialBox getLocalAxialBox ( void ) const;
// ----------
Transform getTransform_l2p ( void ) const;
Transform getTransform_p2l ( void ) const;
protected:
BaseType m_baseType;
ShapeType m_shapeType;
Vector m_center;
Vector m_axisX;
Vector m_axisY;
Vector m_axisZ;
float m_extentX;
float m_extentY;
float m_extentZ;
};
// ----------------------------------------------------------------------
inline MultiShape::BaseType MultiShape::getBaseType ( void ) const
{
return m_baseType;
}
inline MultiShape::ShapeType MultiShape::getShapeType ( void ) const
{
return m_shapeType;
}
// ----------
inline Vector const & MultiShape::getCenter ( void ) const
{
return m_center;
}
// ----------
inline Vector const & MultiShape::getAxisX ( void ) const
{
return m_axisX;
}
inline Vector const & MultiShape::getAxisY ( void ) const
{
return m_axisY;
}
inline Vector const & MultiShape::getAxisZ ( void ) const
{
return m_axisZ;
}
// ----------
inline float MultiShape::getExtentX ( void ) const
{
return m_extentX;
}
inline float MultiShape::getExtentY ( void ) const
{
return m_extentY;
}
inline float MultiShape::getExtentZ ( void ) const
{
return m_extentZ;
}
// ----------
inline void MultiShape::setExtentX ( float newExtent )
{
m_extentX = newExtent;
}
inline void MultiShape::setExtentY ( float newExtent )
{
m_extentY = newExtent;
}
inline void MultiShape::setExtentZ ( float newExtent )
{
m_extentZ = newExtent;
}
// ----------------------------------------------------------------------
inline Vector MultiShape::getBase ( void ) const
{
return getCenter() - getAxisY() * getExtentY();
}
// ----------
inline float MultiShape::getWidth ( void ) const
{
return getExtentX() * 2.0f;
}
inline float MultiShape::getHeight ( void ) const
{
return getExtentY() * 2.0f;
}
inline float MultiShape::getDepth ( void ) const
{
return getExtentZ() * 2.0f;
}
// ======================================================================
#endif
@@ -0,0 +1,133 @@
// ======================================================================
//
// OrientedBox.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/OrientedBox.h"
#include "sharedMath/Plane3d.h"
#include "sharedMath/Transform.h"
#include "sharedMath/AxialBox.h"
#include "sharedMath/YawedBox.h"
// ----------------------------------------------------------------------
OrientedBox::OrientedBox ( AxialBox const & s, Transform const & tform )
: m_center ( tform.rotateTranslate_l2p(s.getCenter()) ),
m_axisX ( tform.rotate_l2p(s.getAxisX()) ),
m_axisY ( tform.rotate_l2p(s.getAxisY()) ),
m_axisZ ( tform.rotate_l2p(s.getAxisZ()) ),
m_extentX ( s.getExtentX() ),
m_extentY ( s.getExtentY() ),
m_extentZ ( s.getExtentZ() )
{
}
// ----------
OrientedBox::OrientedBox ( AxialBox const & s )
: m_center ( s.getCenter() ),
m_axisX ( s.getAxisX() ),
m_axisY ( s.getAxisY() ),
m_axisZ ( s.getAxisZ() ),
m_extentX ( s.getExtentX() ),
m_extentY ( s.getExtentY() ),
m_extentZ ( s.getExtentZ() )
{
}
// ----------
OrientedBox::OrientedBox ( YawedBox const & s )
: m_center ( s.getCenter() ),
m_axisX ( s.getAxisX() ),
m_axisY ( s.getAxisY() ),
m_axisZ ( s.getAxisZ() ),
m_extentX ( s.getExtentX() ),
m_extentY ( s.getExtentY() ),
m_extentZ ( s.getExtentZ() )
{
}
// ----------------------------------------------------------------------
Plane3d OrientedBox::getFacePlane ( int whichFace ) const
{
switch(whichFace)
{
case 0: return Plane3d( m_center + m_axisX * m_extentX, m_axisX );
case 1: return Plane3d( m_center + m_axisY * m_extentY, m_axisY );
case 2: return Plane3d( m_center + m_axisZ * m_extentZ, m_axisZ );
case 3: return Plane3d( m_center - m_axisX * m_extentX, -m_axisX );
case 4: return Plane3d( m_center - m_axisY * m_extentY, -m_axisY );
case 5: return Plane3d( m_center - m_axisZ * m_extentZ, -m_axisZ );
default:
DEBUG_FATAL(true,("OrientedBox::getFacePlane - invalid face\n"));
return Plane3d(Vector::zero,Vector::zero);
}
}
// ----------------------------------------------------------------------
AxialBox OrientedBox::getLocalShape ( void ) const
{
return AxialBox( Vector(-m_extentX,-m_extentY,-m_extentZ),
Vector( m_extentX, m_extentY, m_extentZ) );
}
Transform OrientedBox::getTransform_l2p ( void ) const
{
Transform temp;
temp.setLocalFrameIJK_p( getAxisX(), getAxisY(), getAxisZ() );
temp.move_p( m_center );
return temp;
}
Transform OrientedBox::getTransform_p2l ( void ) const
{
Transform temp;
temp.invert(getTransform_l2p());
return temp;
}
Vector OrientedBox::transformToLocal( Vector const & V ) const
{
return rotateToLocal( V - m_center );
}
Vector OrientedBox::transformToWorld ( Vector const & V ) const
{
return rotateToWorld(V) + m_center;
}
Vector OrientedBox::rotateToLocal ( Vector const & V ) const
{
Vector temp;
temp.x = V.dot(getAxisX());
temp.y = V.dot(getAxisY());
temp.z = V.dot(getAxisZ());
return temp;
}
Vector OrientedBox::rotateToWorld ( Vector const & V ) const
{
Vector temp = Vector::zero;
temp += getAxisX() * V.x;
temp += getAxisY() * V.y;
temp += getAxisZ() * V.z;
return temp;
}
// ----------------------------------------------------------------------
@@ -0,0 +1,182 @@
// ======================================================================
//
// OrientedBox.h
// copyright (c) 2001 Sony Online Entertainment
//
// ----------------------------------------------------------------------
#ifndef INCLUDED_OrientedBox_H
#define INCLUDED_OrientedBox_H
#include "sharedMath/Vector.h"
class Plane3d;
class AxialBox;
class YawedBox;
class Transform;
// ======================================================================
class OrientedBox
{
public:
OrientedBox ( Vector const & center,
Vector const & i, Vector const & j, Vector const & k,
real extentI, real extentJ, real extentK );
OrientedBox ( AxialBox const & box, Transform const & tform );
explicit OrientedBox ( AxialBox const & box );
explicit OrientedBox ( YawedBox const & box );
// ----------
Vector const * getAxes ( void ) const;
float const * getExtents ( void ) const;
Vector getBase ( void ) const;
Plane3d getFacePlane ( int whichPlane ) const;
Vector getCorner ( int whichCorner ) const;
// ----------
Vector const & getCenter ( void ) const;
Vector const & getAxisX ( void ) const;
Vector const & getAxisY ( void ) const;
Vector const & getAxisZ ( void ) const;
float getExtentX ( void ) const;
float getExtentY ( void ) const;
float getExtentZ ( void ) const;
// ----------
AxialBox getLocalShape ( void ) const;
Transform getTransform_l2p ( void ) const;
Transform getTransform_p2l ( void ) const;
Vector transformToLocal ( Vector const & V ) const;
Vector transformToWorld ( Vector const & V ) const;
Vector rotateToLocal ( Vector const & V ) const;
Vector rotateToWorld ( Vector const & V ) const;
protected:
Vector m_center;
Vector m_axisX;
Vector m_axisY;
Vector m_axisZ;
float m_extentX;
float m_extentY;
float m_extentZ;
};
// ----------------------------------------------------------------------
inline OrientedBox::OrientedBox( Vector const & center,
Vector const & axisX,
Vector const & axisY,
Vector const & axisZ,
real extentX,
real extentY,
real extentZ )
: m_center(center),
m_axisX(axisX),
m_axisY(axisY),
m_axisZ(axisZ),
m_extentX(extentX),
m_extentY(extentY),
m_extentZ(extentZ)
{
}
// ----------------------------------------------------------------------
inline Vector const * OrientedBox::getAxes ( void ) const
{
return &m_axisX;
}
inline float const * OrientedBox::getExtents ( void ) const
{
return &m_extentX;
}
inline Vector OrientedBox::getBase ( void ) const
{
return getCenter() - getAxisY() * getExtentY();
}
inline Vector OrientedBox::getCorner ( int whichCorner ) const
{
Vector X = m_axisX * m_extentX;
Vector Y = m_axisY * m_extentY;
Vector Z = m_axisZ * m_extentZ;
switch(whichCorner)
{
case 0: return m_center - X - Y - Z;
case 1: return m_center + X - Y - Z;
case 2: return m_center - X - Y + Z;
case 3: return m_center + X - Y + Z;
case 4: return m_center - X + Y - Z;
case 5: return m_center + X + Y - Z;
case 6: return m_center - X + Y + Z;
case 7: return m_center + X + Y + Z;
default: return Vector(0,0,0);
}
}
// ----------------------------------------------------------------------
inline Vector const & OrientedBox::getCenter ( void ) const
{
return m_center;
}
// ----------
inline Vector const & OrientedBox::getAxisX ( void ) const
{
return m_axisX;
}
inline Vector const & OrientedBox::getAxisY ( void ) const
{
return m_axisY;
}
inline Vector const & OrientedBox::getAxisZ ( void ) const
{
return m_axisZ;
}
// ----------
inline float OrientedBox::getExtentX ( void ) const
{
return m_extentX;
}
inline float OrientedBox::getExtentY ( void ) const
{
return m_extentY;
}
inline float OrientedBox::getExtentZ ( void ) const
{
return m_extentZ;
}
// ----------------------------------------------------------------------
#endif
@@ -0,0 +1,28 @@
// ======================================================================
//
// OrientedCircle.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/OrientedCircle.h"
#include "sharedMath/Circle.h"
OrientedCircle::OrientedCircle ( Vector const & center, Vector const & axis, float radius )
: m_center(center),
m_axis(axis),
m_radius(radius)
{
}
OrientedCircle::OrientedCircle ( Circle const & circle )
: m_center( circle.getCenter() ),
m_axis( Vector(0,1,0) ),
m_radius( circle.getRadius() )
{
}
@@ -0,0 +1,57 @@
// ======================================================================
//
// OrientedCircle.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_OrientedCircle_H
#define INCLUDED_OrientedCircle_H
#include "sharedMath/Vector.h"
class Circle;
// ======================================================================
class OrientedCircle
{
public:
OrientedCircle ( Vector const & center, Vector const & axis, float radius );
OrientedCircle ( Circle const & circle );
Vector const & getAxis ( void ) const;
float getRadius ( void ) const;
Vector const & getCenter ( void ) const;
protected:
Vector m_center;
Vector m_axis;
float m_radius;
};
// ----------------------------------------------------------------------
inline Vector const & OrientedCircle::getAxis ( void ) const
{
return m_axis;
}
inline float OrientedCircle::getRadius ( void ) const
{
return m_radius;
}
inline Vector const & OrientedCircle::getCenter ( void ) const
{
return m_center;
}
// ======================================================================
#endif
@@ -0,0 +1,121 @@
// ======================================================================
//
// OrientedCylinder.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/OrientedCylinder.h"
#include "sharedMath/Transform.h"
#include "sharedMath/Range.h"
#include "sharedMath/Cylinder.h"
#include "sharedMath/OrientedCircle.h"
#include "sharedMath/Segment3d.h"
// ----------------------------------------------------------------------
OrientedCylinder::OrientedCylinder ( Cylinder const & s )
: m_base ( s.getBase() ),
m_axis ( Vector::unitY ),
m_radius ( s.getRadius() ),
m_height ( s.getHeight() )
{
}
OrientedCylinder::OrientedCylinder ( Cylinder const & s, Transform const & tform )
: m_base ( tform.rotateTranslate_l2p(s.getBase()) ),
m_axis ( tform.rotate_l2p(s.getAxisY()) ),
m_radius ( s.getRadius() ),
m_height ( s.getHeight() )
{
}
// ----------------------------------------------------------------------
Segment3d OrientedCylinder::getAxisSegment ( void ) const
{
return Segment3d( m_base, m_base + m_axis * m_height );
}
OrientedCircle OrientedCylinder::getBaseCircle ( void ) const
{
return OrientedCircle(m_base,m_axis,m_radius);
}
OrientedCircle OrientedCylinder::getTopCircle ( void ) const
{
return OrientedCircle(m_base + m_axis * m_height,m_axis,m_radius);
}
// ----------------------------------------------------------------------
Cylinder OrientedCylinder::getLocalShape ( void ) const
{
float extentY = getExtentY();
return Cylinder( Vector(0,-extentY,0), m_radius, extentY * 2.0f );
}
Transform OrientedCylinder::getTransform_l2p ( void ) const
{
Transform temp;
temp.setLocalFrameIJK_p( getAxisX(), getAxisY(), getAxisZ() );
temp.move_p( getCenter() );
return temp;
}
Transform OrientedCylinder::getTransform_p2l ( void ) const
{
Transform temp;
temp.invert(getTransform_l2p());
return temp;
}
Vector OrientedCylinder::transformToLocal ( Vector const & V ) const
{
return rotateToLocal(V - getCenter());
}
Vector OrientedCylinder::transformToWorld ( Vector const & V ) const
{
return rotateToWorld(V) + getCenter();
}
Vector OrientedCylinder::rotateToLocal ( Vector const & V ) const
{
Vector temp;
Vector axisX = getAxisX();
Vector axisY = getAxisY();
Vector axisZ = getAxisZ();
temp.x = V.dot(axisX);
temp.y = V.dot(axisY);
temp.z = V.dot(axisZ);
return temp;
}
Vector OrientedCylinder::rotateToWorld ( Vector const & V ) const
{
Vector temp = Vector::zero;
Vector axisX = getAxisX();
Vector axisY = getAxisY();
Vector axisZ = getAxisZ();
temp += axisX * V.x;
temp += axisY * V.y;
temp += axisZ * V.z;
return temp;
}
// ----------------------------------------------------------------------
@@ -0,0 +1,175 @@
// ======================================================================
//
// OrientedCylinder.h
// copyright (c) 2001 Sony Online Entertainment
//
// ----------------------------------------------------------------------
#ifndef INCLUDED_OrientedCylinder_H
#define INCLUDED_OrientedCylinder_H
#include "sharedMath/Vector.h"
class Transform;
class Range;
class Cylinder;
class OrientedCircle;
class Segment3d;
// ======================================================================
class OrientedCylinder
{
public:
OrientedCylinder();
OrientedCylinder ( Vector const & base, Vector const & axis, float radius, float height );
explicit OrientedCylinder ( Cylinder const & cyl );
OrientedCylinder( Cylinder const & s, Transform const & tform );
// ----------
Vector const & getBase ( void ) const;
Vector const & getAxis ( void ) const;
float getRadius ( void ) const;
float getHeight ( void ) const;
// ----------
// Sub-shapes
Segment3d getAxisSegment ( void ) const;
OrientedCircle getBaseCircle ( void ) const;
OrientedCircle getTopCircle ( void ) const;
// ----------
Vector getCenter ( void ) const;
Vector getAxisX ( void ) const;
Vector getAxisY ( void ) const;
Vector getAxisZ ( void ) const;
float getExtentX ( void ) const;
float getExtentY ( void ) const;
float getExtentZ ( void ) const;
// ----------
Transform getTransform_l2p ( void ) const;
Transform getTransform_p2l ( void ) const;
Vector transformToLocal ( Vector const & V ) const;
Vector transformToWorld ( Vector const & V ) const;
Vector rotateToLocal ( Vector const & V ) const;
Vector rotateToWorld ( Vector const & V ) const;
Cylinder getLocalShape ( void ) const;
protected:
Vector m_base;
Vector m_axis;
float m_radius;
float m_height;
};
// ----------------------------------------------------------------------
inline OrientedCylinder::OrientedCylinder ()
: m_base( Vector::zero ),
m_axis( Vector(0.0f,1.0f,0.0f) ),
m_radius( 1.0f ),
m_height( 1.0f )
{
}
inline OrientedCylinder::OrientedCylinder ( Vector const & base, Vector const & axis, float radius, float height )
: m_base( base ),
m_axis( axis ),
m_radius( radius ),
m_height( height )
{
IGNORE_RETURN(m_axis.normalize());
}
// ----------
inline Vector const & OrientedCylinder::getBase ( void ) const
{
return m_base;
}
inline Vector const & OrientedCylinder::getAxis ( void ) const
{
return m_axis;
}
inline float OrientedCylinder::getRadius ( void ) const
{
return m_radius;
}
inline float OrientedCylinder::getHeight ( void ) const
{
return m_height;
}
// ----------------------------------------------------------------------
inline Vector OrientedCylinder::getCenter ( void ) const
{
return m_base + m_axis * (m_height / 2.0f);
}
inline Vector OrientedCylinder::getAxisX ( void ) const
{
Vector projected(-m_axis.z,0.0f,m_axis.x);
if(projected.normalize())
{
return projected;
}
else
{
return Vector::unitX;
}
}
inline Vector OrientedCylinder::getAxisY ( void ) const
{
return m_axis;
}
inline Vector OrientedCylinder::getAxisZ ( void ) const
{
Vector temp = getAxisX().cross(m_axis);
temp.normalize();
return temp;
}
inline float OrientedCylinder::getExtentX ( void ) const
{
return m_radius;
}
inline float OrientedCylinder::getExtentY ( void ) const
{
return m_height / 2.0f;
}
inline float OrientedCylinder::getExtentZ ( void ) const
{
return m_radius;
}
// ======================================================================
#endif
@@ -0,0 +1,17 @@
// ======================================================================
//
// Plane3d.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Plane3d.h"
#include "sharedMath/Plane.h"
Plane3d::Plane3d ( Plane const & plane )
: m_point( plane.getNormal() * -plane.getD() ),
m_normal( plane.getNormal() )
{
}
@@ -0,0 +1,91 @@
// ======================================================================
//
// Plane3d.h
// copyright (c) 2001 Sony Online Entertainment
//
// ----------------------------------------------------------------------
#ifndef INCLUDED_Plane3d_H
#define INCLUDED_Plane3d_H
#include "sharedMath/Vector.h"
class Plane;
// ----------------------------------------------------------------------
class Plane3d
{
public:
Plane3d();
Plane3d ( Plane const & plane );
Plane3d ( Vector const & p, Vector const & n );
Plane3d ( Vector const & A, Vector const & B, Vector const & C );
// build a plane but don't worry about normalizing the m_normal
static Plane3d NoNorm( Vector const & p, Vector const & n );
Vector const & getPoint ( void ) const;
Vector const & getNormal ( void ) const;
bool isNormalized ( void ) const; //@return True if the plane's normal is unit-length
protected:
Vector m_point;
Vector m_normal;
};
// ----------
inline Plane3d::Plane3d()
{
}
inline Plane3d::Plane3d ( Vector const & p, Vector const & n )
: m_point(p), m_normal(n)
{
IGNORE_RETURN( m_normal.normalize() );
}
inline Plane3d::Plane3d ( Vector const & A, Vector const & B, Vector const & C )
: m_point(A), m_normal( (B-A).cross(C-A) )
{
IGNORE_RETURN( m_normal.normalize() );
}
// build a plane but don't worry about normalizing the m_normal
inline Plane3d Plane3d::NoNorm( Vector const & p, Vector const & n )
{
Plane3d temp;
temp.m_point = p;
temp.m_normal = n;
return temp;
}
inline Vector const & Plane3d::getPoint ( void ) const
{
return m_point;
}
inline Vector const & Plane3d::getNormal ( void ) const
{
return m_normal;
}
inline bool Plane3d::isNormalized ( void ) const
{
// return m_normal.isNormalized()
return true;
}
// ----------------------------------------------------------------------
#endif // #ifdef INCLUDED_Plane3d_H
@@ -0,0 +1,68 @@
// ======================================================================
//
// Quadratic.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Quadratic.h"
bool Quadratic::solveFor ( float value, float & out1, float & out2 ) const
{
if((m_A == 0.0f) && (m_B == 0.0f))
{
if(m_C == value)
{
out1 = -REAL_MAX;
out2 = REAL_MAX;
return true;
}
else
{
return false;
}
}
// ----------
if(m_A == 0.0f)
{
out1 = (value - m_C) / m_B;
out2 = (value - m_C) / m_B;
return true;
}
// ----------
float a = m_A;
float b = m_B;
float c = m_C - value;
float det = b*b - 4*a*c;
if(det < 0) return false;
float s = sqrt(det);
float i = 1.0f / (2.0f * a);
float o1 = (-b + s) * i;
float o2 = (-b - s) * i;
if(o1 < o2)
{
out1 = o1;
out2 = o2;
}
else
{
out1 = o2;
out2 = o1;
}
return true;
}
@@ -0,0 +1,42 @@
// ======================================================================
//
// Quadratic.h
// copyright (c) 2001 Sony Online Entertainment
//
// Simple class to represent a quadratic equation
//
// ----------------------------------------------------------------------
#ifndef INCLUDED_Quadratic_H
#define INCLUDED_Quadratic_H
// ======================================================================
class Quadratic
{
public:
Quadratic ( float a, float b, float c );
// ----------
bool solveFor( float value, float & out1, float & out2 ) const;
// ----------
float m_A;
float m_B;
float m_C;
};
// ----------------------------------------------------------------------
inline Quadratic::Quadratic ( float a, float b, float c )
: m_A(a), m_B(b), m_C(c)
{
}
// ----------------------------------------------------------------------
#endif
@@ -0,0 +1,71 @@
// ======================================================================
//
// Range.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Range.h"
#include "sharedRandom/Random.h"
#include <algorithm>
Range Range::empty ( REAL_MAX, -REAL_MAX );
Range Range::inf ( -REAL_MAX, REAL_MAX );
Range Range::plusInf ( 0.0f, REAL_MAX );
Range Range::negInf (-REAL_MAX,0.0f);
Range Range::unit (0.0f,1.0f);
Range Range::enclose ( Range const & A, float V )
{
if(A.isEmpty())
{
return Range(V,V);
}
else
{
return Range(std::min(A.getMin(),V),std::max(A.getMax(),V));
}
}
Range Range::enclose ( Range const & A, Range const & B )
{
if(A.isEmpty())
{
if(B.isEmpty())
{
return Range::empty;
}
else
{
return B;
}
}
else
{
if(B.isEmpty())
{
return A;
}
else
{
return Range(std::min(A.getMin(),B.getMin()), std::max(A.getMax(),B.getMax()));
}
}
}
Range Range::enclose ( Range const & A, Range const & B, Range const & C )
{
return enclose(enclose(A,B),C);
}
Range Range::enclose ( Range const & A, Range const & B, Range const & C, Range const & D )
{
return enclose(enclose(A,B),enclose(C,D));
}
float Range::random() const
{
return (m_min > m_max) ? Random::randomReal(m_max, m_min) : Random::randomReal(m_min, m_max);
}
@@ -0,0 +1,225 @@
// ======================================================================
//
// Range.h
// copyright (c) 2001 Sony Online Entertainment
//
// Simple class to represent a 1D range (essentially a 1d bounding box)
//
// ----------------------------------------------------------------------
#ifndef INCLUDED_Range_H
#define INCLUDED_Range_H
#include "sharedFoundation/Misc.h"
// ======================================================================
class Range
{
public:
Range();
Range( float newMin, float newMax );
// ----------
float const & getMin ( void ) const;
float const & getMax ( void ) const;
void setMin ( float const & newMin );
void setMax ( float const & newMax );
void set(float const newMin, float const newMax );
// ----------
bool isBelow ( Range const & R ) const;
bool isAbove ( Range const & R ) const;
bool isTouchingBelow ( Range const & R ) const;
bool isTouchingAbove ( Range const & R ) const;
bool isEmpty ( void ) const;
// ----------
bool contains ( float V ) const;
Range operator + ( float offset ) const;
bool operator < ( Range const & R ) const;
bool operator == ( Range const & R ) const;
bool operator != ( Range const & R ) const;
float clamp ( float V ) const;
float linearInterpolate(float t) const;
float cubicInterpolate(float t) const;
float random() const;
// ----------
static Range empty;
static Range inf; // (-inf,inf)
static Range plusInf; // (0,inf)
static Range negInf; // (-inf,0)
static Range unit; // (0,1)
// ----------
static Range enclose ( Range const & A, float V );
static Range enclose ( Range const & A, Range const & B );
static Range enclose ( Range const & A, Range const & B, Range const & C );
static Range enclose ( Range const & A, Range const & B, Range const & C, Range const & D );
protected:
float m_min;
float m_max;
};
// ----------------------------------------------------------------------
inline Range::Range() : m_min(REAL_MAX), m_max(-REAL_MAX)
{
}
inline Range::Range ( float newMin, float newMax ) : m_min(newMin), m_max(newMax)
{
}
// ----------
inline float const & Range::getMin ( void ) const
{
return m_min;
}
inline float const & Range::getMax ( void ) const
{
return m_max;
}
inline void Range::setMin ( float const & newMin )
{
m_min = newMin;
}
inline void Range::setMax ( float const & newMax )
{
m_max = newMax;
}
inline void Range::set(float const newMin, float const newMax )
{
setMin(newMin);
setMax(newMax);
}
// ----------
inline bool Range::isBelow ( Range const & R ) const
{
return m_max < R.m_min;
}
inline bool Range::isAbove ( Range const & R ) const
{
return m_min > R.m_max;
}
inline bool Range::isTouchingBelow ( Range const & R ) const
{
return m_max == R.m_min;
}
inline bool Range::isTouchingAbove ( Range const & R ) const
{
return m_min == R.m_max;
}
inline bool Range::isEmpty ( void ) const
{
return m_max < m_min;
}
// ----------
inline bool Range::contains ( float V ) const
{
if(V < m_min) return false;
if(V > m_max) return false;
return true;
}
// ----------
inline Range Range::operator + ( float offset ) const
{
return Range(m_min + offset, m_max + offset);
}
inline bool Range::operator < ( Range const & R ) const
{
if( m_min < R.m_min )
{
return true;
}
else if( m_min == R.m_min )
{
return m_max < R.m_max;
}
else
{
return false;
}
}
inline bool Range::operator == ( Range const & R ) const
{
if(m_min != R.m_min) return false;
if(m_max != R.m_max) return false;
return true;
}
inline bool Range::operator != ( Range const & R ) const
{
if(m_min != R.m_min) return true;
if(m_max != R.m_max) return true;
return false;
}
// ----------
inline float Range::clamp ( float V ) const
{
if(isEmpty())
{
return V;
}
else
{
return ::clamp(m_min, V, m_max);
}
}
// ----------
inline float Range::linearInterpolate(float const t) const
{
return ::linearInterpolate(m_min, m_max, t);
}
// ----------
inline float Range::cubicInterpolate(float const t) const
{
return ::cubicInterpolate(m_min, m_max, t);
}
// ------------------------------------------------::----------------------
#endif
@@ -0,0 +1,458 @@
// ======================================================================
//
// RangeLoop.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/RangeLoop.h"
#include "sharedFoundation/ConfigFile.h"
#include "sharedMath/ConfigSharedMath.h"
// ----------
float RangeLoop::clip ( float x )
{
return x - (float)floor(x);
}
// distance you have to go in the positive direction to get from A to B
float RangeLoop::distancePositive ( float A, float B )
{
A = clip(A);
B = clip(B);
return (B > A) ? -A + B : 1 - A + B;
}
// distance you have to go in the negative direction to get from A to B
float RangeLoop::distanceNegative ( float A, float B )
{
A = clip(A);
B = clip(B);
return (B > A) ? 1 + A - B : A - B;
}
bool RangeLoop::containsInclusive ( float min, float max, float x )
{
min = clip(min);
max = clip(max);
x = clip(x);
if(max > min)
{
return ( x >= min ) && ( x <= max );
}
else
{
return ( x >= min ) || ( x <= max );
}
}
// distancePositive(A,B) + distanceNegative(A,B) == 1.0
// signed distance from A to B via whichever way's closer
float distance ( float A, float B )
{
A = RangeLoop::clip(A);
B = RangeLoop::clip(B);
float positive = RangeLoop::distancePositive(A,B);
if(positive <= 0.5)
{
return positive;
}
else
{
return positive-1;
}
}
// ======================================================================
RangeLoop::RangeLoop ( void )
: m_min( -1.0f ),
m_max( -1.0f )
{
}
RangeLoop::RangeLoop ( float min, float max )
: m_min( clip(min) ),
m_max( clip(max) )
{
if(abs(max-min) >= 1.0f)
{
m_min = 0.0f;
m_max = 1.0f;
}
}
// ----------
RangeLoop RangeLoop::empty;
RangeLoop RangeLoop::full(0.0f,1.0f);
// ----------------------------------------------------------------------
bool RangeLoop::isEmpty ( void ) const
{
return (m_min == -1.0f) && (m_max == -1.0f);
}
bool RangeLoop::isFull ( void ) const
{
return (m_min == 0.0f) && (m_max == 1.0f);
}
float RangeLoop::atParam ( float t ) const
{
if(m_min <= m_max)
{
return m_min + (m_max - m_min) * t;
}
else
{
return clip( m_min + (m_max - m_min + 1.0f) * t );
}
}
float RangeLoop::getSize ( void ) const
{
if(m_min <= m_max)
{
return m_max - m_min;
}
else
{
return m_max - m_min + 1.0f;
}
}
// ----------------------------------------------------------------------
// true if
// [----R----]
// xxxxxxxxxxx
bool RangeLoop::containsInclusive ( float x ) const
{
if(isFull()) return true;
if(isEmpty()) return false;
x = clip(x);
if(m_max == m_min)
{
return x == m_min;
}
else if(m_max > m_min)
{
return ( x >= m_min ) && ( x <= m_max );
}
else
{
return ( x >= m_min ) || ( x <= m_max );
}
}
// ----------
// true if
// (----R----)
// xxxxxxxxx
bool RangeLoop::containsExclusive ( float x ) const
{
if(isFull()) return true;
if(isEmpty()) return false;
x = clip(x);
if(m_max == m_min)
{
return x == m_min;
}
else if(m_max > m_min)
{
return ( x > m_min ) && ( x < m_max );
}
else
{
return ( x > m_min ) || ( x < m_max );
}
}
// ----------
// true if
// (----A----)
// (----B----)
bool RangeLoop::overlapPositive ( RangeLoop const & R ) const
{
if(isEmpty() || R.isEmpty()) return false;
if(isFull() || R.isFull()) return true;
if(!containsExclusive(R.m_min)) return false;
if( containsExclusive(R.m_max)) return false;
if(!R.containsExclusive(m_max)) return false;
if( R.containsExclusive(m_min)) return false;
return true;
}
// true if
// (----B----)
// (----A----)
bool RangeLoop::overlapNegative ( RangeLoop const & R ) const
{
if(isEmpty() || R.isEmpty()) return false;
if(isFull() || R.isFull()) return true;
if(!containsExclusive(R.m_max)) return false;
if( containsExclusive(R.m_min)) return false;
if(!R.containsExclusive(m_min)) return false;
if( R.containsExclusive(m_max)) return false;
return true;
}
// true if
// [--A--]
// [--B--]
bool RangeLoop::disjointInclusive ( RangeLoop const & R ) const
{
if(isEmpty() || R.isEmpty()) return false;
if(isFull() || R.isFull()) return true;
if(containsInclusive(R.m_min)) return false;
if(containsInclusive(R.m_max)) return false;
if(R.containsInclusive(m_min)) return false;
if(R.containsInclusive(m_max)) return false;
return true;
}
// true if
// (--A--)
// (--B--)
bool RangeLoop::disjointExclusive ( RangeLoop const & R ) const
{
if(isEmpty() || R.isEmpty()) return true;
if(isFull() || R.isFull()) return false;
if(containsExclusive(R.m_min)) return false;
if(containsExclusive(R.m_max)) return false;
if(R.containsExclusive(m_min)) return false;
if(R.containsExclusive(m_max)) return false;
return true;
}
bool RangeLoop::contains ( RangeLoop const & R ) const
{
if(isEmpty() || R.isEmpty()) return false;
if(isFull()) return true;
if(R.isFull()) return false;
if(!containsInclusive(R.m_min)) return false;
if(!containsInclusive(R.m_max)) return false;
return true;
}
bool RangeLoop::operator == ( RangeLoop const & R ) const
{
if(m_min != R.m_min) return false;
if(m_max != R.m_max) return false;
return true;
}
// ----------
RangeLoop RangeLoop::enclose ( float A, float B )
{
if(distancePositive(A,B) < 0.5f)
{
return RangeLoop(A,B);
}
else
{
return RangeLoop(B,A);
}
}
RangeLoop RangeLoop::enclose ( RangeLoop const & A, float B )
{
if(A.isEmpty())
{
return RangeLoop(B,B);
}
else if(A.isFull())
{
return RangeLoop::full;
}
else if(A.containsInclusive(B))
{
return A;
}
else
{
float distA = distancePositive(A.getMax(),B);
float distB = distanceNegative(A.getMin(),B);
if(distA < distB)
{
return RangeLoop(A.getMin(),B);
}
else
{
return RangeLoop(B,A.getMax());
}
}
}
RangeLoop RangeLoop::enclose ( RangeLoop const & A, RangeLoop const & B )
{
#ifdef _DEBUG
A.validate();
B.validate();
#endif
// ----------
// check full ranges
bool fullA = A.isFull();
bool fullB = B.isFull();
if(fullA || fullB)
{
return RangeLoop::full;
}
// ----------
// check empty ranges
bool emptyA = A.isEmpty();
bool emptyB = B.isEmpty();
if(emptyA && emptyB)
{
return RangeLoop::empty;
}
else if(emptyA)
{
return B;
}
else if(emptyB)
{
return A;
}
// ----------
// check containing/disjoint ranges
if(A.contains(B))
{
return A;
}
else if(B.contains(A))
{
return B;
}
else if (A.disjointExclusive(B))
{
float distA = distancePositive(A.getMin(),B.getMax());
float distB = distanceNegative(A.getMax(),B.getMin());
if(distA < distB)
{
return RangeLoop(A.getMin(),B.getMax());
}
else
{
return RangeLoop(B.getMin(),A.getMax());
}
}
// ----------
// check overlapping ranges
bool overlapAB = A.overlapPositive(B);
bool overlapBA = B.overlapPositive(A);
if(overlapAB && overlapBA)
{
return RangeLoop(0.0f,1.0f);
}
else if(overlapAB)
{
return RangeLoop(A.getMin(),B.getMax());
}
else if(overlapBA)
{
return RangeLoop(B.getMin(),A.getMax());
}
// ----------
// check adjacent ranges
bool touchAB = (A.getMax() == B.getMin());
bool touchBA = (B.getMax() == A.getMin());
if(touchAB && touchBA)
{
return RangeLoop(0.0f,1.0f);
}
else if(touchAB)
{
return RangeLoop(A.getMin(),B.getMax());
}
else if(touchBA)
{
return RangeLoop(B.getMin(),A.getMax());
}
// ----------
// something's screwed up - we should have caught all the cases by now
WARNING_STRICT_FATAL(ConfigSharedMath::getReportRangeLoopWarnings(),("RangeLoop::enclose is broken - (%f,%f) (%f,%f)\n",A.getMin(),A.getMax(),B.getMin(),B.getMax()));
return RangeLoop(0.0f,1.0f);
}
// ----------------------------------------------------------------------
void RangeLoop::validate ( void ) const
{
#ifdef _DEBUG
if(isFull()) return;
if(isEmpty()) return;
if((m_min < 0.0f) || (m_max >= 1.0f))
{
DEBUG_WARNING(ConfigSharedMath::getReportRangeLoopWarnings(),("RangeLoop::validate - range (%f,%f) is invalid\n",m_min,m_max));
}
#endif
}
// ======================================================================
@@ -0,0 +1,120 @@
// ======================================================================
//
// RangeLoop.h
// copyright (c) 2001 Sony Online Entertainment
//
// This class requires a bit of explanation - it represents a 1d range
// of numbers defined over the numerical ring [0,1). Because the ring
// is closed, certain operations aren't well-defined - there's no
// way to express the notions of "greater than" or "less than" nor is
// there a unique way to express the distance between two values.
// Nevertheless, this class is very useful for representing ranges of
// things that are logically loops, like angles and such.
// Definitions -
// [ 0 ,0.2 ] - all numbers between 0 and 0.2, inclusive
// [ 0.4, 0.2 ] - the union of [ 0.4, 1 ) and [ 0, 0.2 ]
// This class really ought to be called RingRange
// ----------------------------------------------------------------------
#ifndef INCLUDED_RangeLoop_H
#define INCLUDED_RangeLoop_H
// ======================================================================
class RangeLoop
{
public:
RangeLoop();
RangeLoop( float newMin, float newMax );
static RangeLoop empty;
static RangeLoop full;
// ----------
bool isEmpty ( void ) const;
bool isFull ( void ) const;
float getMin ( void ) const;
float getMax ( void ) const;
void setMin ( float newMin );
void setMax ( float newMax );
float atParam ( float t ) const;
float getSize ( void ) const;
// ----------
bool overlapPositive ( RangeLoop const & R ) const; // exclusive test
bool overlapNegative ( RangeLoop const & R ) const; // exclusive test
bool disjointInclusive ( RangeLoop const & R ) const;
bool disjointExclusive ( RangeLoop const & R ) const;
bool containsInclusive ( float V ) const;
bool containsExclusive ( float V ) const;
bool contains ( RangeLoop const & R ) const;
bool operator == ( RangeLoop const & R ) const;
bool operator != ( RangeLoop const & R ) const;
// ----------
// accessory functions
static float clip ( float V );
static float distancePositive ( float A, float B );
static float distanceNegative ( float A, float B );
static bool containsInclusive ( float min, float max, float V );
static RangeLoop enclose ( float A, float B);
static RangeLoop enclose ( RangeLoop const & A, float B);
static RangeLoop enclose ( RangeLoop const & A, RangeLoop const & B);
protected:
void validate ( void ) const;
float m_min;
float m_max;
};
// ----------------------------------------------------------------------
inline float RangeLoop::getMin ( void ) const
{
return m_min;
}
inline float RangeLoop::getMax ( void ) const
{
return m_max;
}
inline void RangeLoop::setMin ( float min )
{
m_min = clip(min);
}
inline void RangeLoop::setMax ( float max )
{
m_max = clip(max);
}
// ======================================================================
#endif
@@ -0,0 +1,18 @@
// ======================================================================
//
// Ray3d.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Ray3d.h"
#include "sharedMath/Line3d.h"
Line3d Ray3d::getLine ( void ) const
{
return Line3d(m_point,m_normal);
}
@@ -0,0 +1,61 @@
// ======================================================================
//
// Ray3d.h
// copyright (c) 2001 Sony Online Entertainment
//
// ----------------------------------------------------------------------
#ifndef INCLUDED_Ray3d_H
#define INCLUDED_Ray3d_H
#include "sharedMath/Vector.h"
class Line3d;
// ----------------------------------------------------------------------
class Ray3d
{
public:
Ray3d ( Vector const & p, Vector const & d );
Vector const & getPoint ( void ) const;
Vector const & getNormal ( void ) const;
Line3d getLine ( void ) const;
Vector atParam ( float t ) const;
protected:
Vector m_point;
Vector m_normal;
};
// ----------
inline Ray3d::Ray3d ( Vector const & p, Vector const & d )
: m_point(p), m_normal(d)
{
}
inline Vector const & Ray3d::getPoint ( void ) const
{
return m_point;
}
inline Vector const & Ray3d::getNormal ( void ) const
{
return m_normal;
}
inline Vector Ray3d::atParam ( float t ) const
{
return m_point + m_normal * t;
}
// ----------------------------------------------------------------------
#endif // #ifdef INCLUDED_Ray3d_H
@@ -0,0 +1,56 @@
// ======================================================================
//
// Ribbon3d.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Ribbon3d.h"
#include "sharedMath/Segment3d.h"
#include "sharedMath/Line3d.h"
#include "sharedMath/Plane3d.h"
Ribbon3d::Ribbon3d ( Vector const & pointA, Vector const & pointB, Vector const & dir )
: m_pointA( pointA ),
m_pointB( pointB ),
m_dir( dir )
{
}
Ribbon3d::Ribbon3d ( Segment3d const & seg, Vector const & dir )
: m_pointA( seg.getBegin() ),
m_pointB( seg.getEnd() ),
m_dir( dir )
{
}
Ribbon3d::Ribbon3d ( Line3d const & line, Vector const & delta )
: m_pointA( line.getPoint() ),
m_pointB( line.getPoint() + delta ),
m_dir( line.getNormal() )
{
}
// ----------
Plane3d Ribbon3d::getPlane( void ) const
{
Vector E = m_pointB - m_pointA;
Vector N = E.cross( m_dir );
return Plane3d( m_pointA, N );
}
Line3d Ribbon3d::getEdgeA( void ) const
{
return Line3d( m_pointA, m_dir );
}
Line3d Ribbon3d::getEdgeB( void ) const
{
return Line3d( m_pointB, m_dir );
}
@@ -0,0 +1,72 @@
// ======================================================================
//
// Ribbon3d.h
// copyright (c) 2001 Sony Online Entertainment
//
// A ribbon is a segment swept along a line.
//
// ----------------------------------------------------------------------
#ifndef INCLUDED_Ribbon3d_H
#define INCLUDED_Ribbon3d_H
#include "sharedMath/Vector.h"
class Segment3d;
class Line3d;
class Plane3d;
// ----------------------------------------------------------------------
class Ribbon3d
{
public:
Ribbon3d ( Vector const & pointA, Vector const & pointB, Vector const & dir );
Ribbon3d ( Segment3d const & seg, Vector const & dir );
Ribbon3d ( Line3d const & line, Vector const & delta );
Vector const & getPointA ( void ) const;
Vector const & getPointB ( void ) const;
Vector const & getDir ( void ) const;
Vector getDelta ( void ) const;
Plane3d getPlane ( void ) const;
Line3d getEdgeA ( void ) const;
Line3d getEdgeB ( void ) const;
protected:
Vector m_pointA;
Vector m_pointB;
Vector m_dir;
};
// ----------------------------------------------------------------------
inline Vector const & Ribbon3d::getPointA ( void ) const
{
return m_pointA;
}
inline Vector const & Ribbon3d::getPointB ( void ) const
{
return m_pointB;
}
inline Vector const & Ribbon3d::getDir ( void ) const
{
return m_dir;
}
inline Vector Ribbon3d::getDelta ( void ) const
{
return m_pointB - m_pointA;
}
// ----------------------------------------------------------------------
#endif // #ifndef INCLUDED_Ribbon3d_H
@@ -0,0 +1,35 @@
// ======================================================================
//
// Ring.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Ring.h"
#include "sharedMath/Range.h"
#include "sharedMath/Plane3d.h"
Range Ring::getRangeX ( void ) const
{
return Range( m_center.x - m_radius, m_center.x + m_radius );
}
Range Ring::getRangeZ ( void ) const
{
return Range( m_center.z - m_radius, m_center.z + m_radius );
}
Range Ring::getLocalRangeX ( void ) const
{
return Range( -m_radius, m_radius );
}
Plane3d Ring::getPlane ( void ) const
{
return Plane3d(m_center,Vector(0,1,0));
}
@@ -0,0 +1,78 @@
// ======================================================================
//
// Ring.h
// copyright (c) 2001 Sony Online Entertainment
//
// Simple class to represent a 2D Ring in the X-Z plane
//
// This class is only semantically different from a Circle - Circles are
// 2-dimensional entities (i.e. a circle cut from paper) whereas a Ring
// is a 1-dimensional entity (a piece of wire bent into a circle)
//
// ----------------------------------------------------------------------
#ifndef INCLUDED_Ring_H
#define INCLUDED_Ring_H
#include "sharedMath/Vector.h"
class Range;
class Plane3d;
// ======================================================================
class Ring
{
public:
Ring ( Vector const & center, float radius );
// ----------
Vector const & getCenter ( void ) const;
float getRadius ( void ) const;
float getRadiusSquared ( void ) const;
Range getRangeX ( void ) const;
Range getRangeZ ( void ) const;
Range getLocalRangeX ( void ) const;
Plane3d getPlane ( void ) const;
protected:
Vector m_center;
float m_radius;
};
// ----------------------------------------------------------------------
inline Ring::Ring ( Vector const & center, float radius )
: m_center(center),
m_radius(radius)
{
}
inline Vector const & Ring::getCenter ( void ) const
{
return m_center;
}
inline float Ring::getRadius ( void ) const
{
return m_radius;
}
inline float Ring::getRadiusSquared ( void ) const
{
return m_radius * m_radius;
}
// ----------------------------------------------------------------------
#endif
@@ -0,0 +1,38 @@
// ======================================================================
//
// Segment3d.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Segment3d.h"
#include "sharedMath/Line3d.h"
#include "sharedMath/Range.h"
Line3d Segment3d::getLine ( void ) const
{
return Line3d(m_begin,m_end-m_begin);
}
Line3d Segment3d::getReverseLine ( void ) const
{
return Line3d(m_end,m_begin-m_end);
}
Range Segment3d::getRangeX ( void ) const
{
return Range(m_begin.x,m_end.x);
}
Range Segment3d::getRangeY ( void ) const
{
return Range(m_begin.y,m_end.y);
}
Range Segment3d::getRangeZ ( void ) const
{
return Range(m_begin.z,m_end.z);
}
@@ -0,0 +1,99 @@
// ======================================================================
//
// Segment3d.h
// copyright (c) 2001 Sony Online Entertainment
//
// ----------------------------------------------------------------------
#ifndef INCLUDED_Segment3d_H
#define INCLUDED_Segment3d_H
#include "sharedMath/Vector.h"
class Line3d;
class Range;
// ----------------------------------------------------------------------
class Segment3d
{
public:
Segment3d ( Vector const & b, Vector const & e );
Vector const & getBegin ( void ) const;
Vector const & getEnd ( void ) const;
Vector & getBegin ( void );
Vector & getEnd ( void );
Vector getDelta ( void ) const;
Line3d getLine ( void ) const;
Line3d getReverseLine ( void ) const;
float getLength ( void ) const;
float getLengthSquared ( void ) const;
Range getRangeX ( void ) const;
Range getRangeY ( void ) const;
Range getRangeZ ( void ) const;
Vector atParam ( float t ) const;
protected:
Vector m_begin;
Vector m_end;
};
// ----------
inline Segment3d::Segment3d ( Vector const & b, Vector const & e )
: m_begin(b), m_end(e)
{
}
inline Vector const & Segment3d::getBegin ( void ) const
{
return m_begin;
}
inline Vector const & Segment3d::getEnd ( void ) const
{
return m_end;
}
inline Vector & Segment3d::getBegin ( void )
{
return m_begin;
}
inline Vector & Segment3d::getEnd ( void )
{
return m_end;
}
inline Vector Segment3d::getDelta ( void ) const
{
return m_end - m_begin;
}
inline float Segment3d::getLength ( void ) const
{
return getDelta().magnitude();
}
inline float Segment3d::getLengthSquared ( void ) const
{
return getDelta().magnitudeSquared();
}
inline Vector Segment3d::atParam ( float t ) const
{
return m_begin + (m_end - m_begin) * t;
}
// ----------------------------------------------------------------------
#endif // #ifndef INCLUDED_Segment3d_H
@@ -0,0 +1,327 @@
// ======================================================================
//
// ShapeUtils.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/ShapeUtils.h"
#include "sharedMath/MultiShape.h"
#include "sharedMath/Transform.h"
#include "sharedMath/Sphere.h"
#include "sharedMath/Cylinder.h"
#include "sharedMath/OrientedCylinder.h"
#include "sharedMath/AxialBox.h"
#include "sharedMath/YawedBox.h"
#include "sharedMath/OrientedBox.h"
#include "sharedMath/Segment3d.h"
#include "sharedMath/Line3d.h"
namespace ShapeUtils
{
// ----------------------------------------------------------------------
MultiShape transform ( MultiShape const & shape, Transform const & tform, float scaleFactor )
{
Vector center = tform.rotateTranslate_l2p( shape.getCenter() * scaleFactor );
Vector axisX = tform.rotate_l2p( shape.getAxisX() );
Vector axisY = tform.rotate_l2p( shape.getAxisY() );
Vector axisZ = tform.rotate_l2p( shape.getAxisZ() );
IGNORE_RETURN( axisX.normalize() );
IGNORE_RETURN( axisY.normalize() );
IGNORE_RETURN( axisZ.normalize() );
// ----------
return MultiShape( shape.getBaseType(),
center,
axisX,
axisY,
axisZ,
shape.getExtentX() * scaleFactor,
shape.getExtentY() * scaleFactor,
shape.getExtentZ() * scaleFactor );
}
// ----------------------------------------------------------------------
Cylinder transform ( Cylinder const & shape, Transform const & tform, float scaleFactor )
{
Cylinder temp = shape;
temp = scale(temp,scaleFactor);
temp = transform_yt(temp,tform);
return temp;
}
OrientedCylinder transform ( OrientedCylinder const & shape, Transform const & tform, float scaleFactor )
{
OrientedCylinder temp = shape;
temp = scale(temp,scaleFactor);
temp = transform_rt(temp,tform);
return temp;
}
Sphere transform ( Sphere const & shape, Transform const & tform, float scaleFactor )
{
Sphere temp = shape;
temp = scale(temp,scaleFactor);
temp = transform_rt(temp,tform);
return temp;
}
AxialBox transform ( AxialBox const & shape, Transform const & tform, float scaleFactor )
{
AxialBox temp = shape;
temp = scale(temp,scaleFactor);
temp = transform_t(temp,tform);
return temp;
}
// ----------------------------------------------------------------------
Segment3d transform_p2l ( Segment3d const & seg, Transform const & tform, float scaleFactor )
{
Vector begin = tform.rotateTranslate_p2l(seg.getBegin());
Vector end = tform.rotateTranslate_p2l(seg.getEnd());
return Segment3d( begin / scaleFactor, end / scaleFactor );
}
Line3d transform_p2l ( Line3d const & line, Transform const & tform, float scaleFactor )
{
Vector point = tform.rotateTranslate_p2l(line.getPoint());
Vector dir = tform.rotate_p2l(line.getNormal());
return Line3d( point / scaleFactor, dir );
}
// ----------------------------------------------------------------------
// Transform-shape-to-world methods
// Translate methods
Sphere translate ( Sphere const & sphere, Vector const & t )
{
Vector center = sphere.getCenter() + t;
return Sphere(center, sphere.getRadius());
}
Cylinder translate ( Cylinder const & cyl, Vector const & t )
{
Vector base = cyl.getBase() + t;
float radius = cyl.getRadius();
float height = cyl.getHeight();
return Cylinder(base,radius,height);
}
AxialBox translate ( AxialBox const & box, Vector const & t )
{
Vector min = box.getMin() + t;
Vector max = box.getMax() + t;
return AxialBox(min,max);
}
MultiShape translate ( MultiShape const & shape, Vector const & t )
{
return MultiShape( shape.getBaseType(),
shape.getShapeType(),
shape.getCenter() + t,
shape.getAxisX(),
shape.getAxisY(),
shape.getAxisZ(),
shape.getExtentX(),
shape.getExtentY(),
shape.getExtentZ() );
}
// ----------
Sphere transform_t ( Sphere const & sphere, Transform const & t )
{
Vector center = t.rotateTranslate_l2p( sphere.getCenter() );
return Sphere(center, sphere.getRadius());
}
Cylinder transform_t ( Cylinder const & cyl, Transform const & t )
{
Vector base = cyl.getBase() + t.getPosition_p();
float radius = cyl.getRadius();
float height = cyl.getHeight();
return Cylinder(base,radius,height);
}
AxialBox transform_t ( AxialBox const & box, Transform const & t )
{
Vector min = box.getMin() + t.getPosition_p();
Vector max = box.getMax() + t.getPosition_p();
return AxialBox(min,max);
}
// ----------
// Yaw-translate methods
Sphere transform_yt ( Sphere const & sphere, Transform const & t )
{
Vector center = t.rotateTranslate_l2p( sphere.getCenter() );
return Sphere(center, sphere.getRadius());
}
Cylinder transform_yt ( Cylinder const & cyl, Transform const & t )
{
Vector base = t.rotateTranslate_l2p( cyl.getBase() );
return Cylinder( base, cyl.getRadius(), cyl.getHeight() );
}
YawedBox transform_yt ( AxialBox const & box, Transform const & t )
{
real yaw = t.getLocalFrameK_p().theta();
Vector center = t.rotateTranslate_l2p( box.getCenter() );
Vector min = center - box.getDelta();
Vector max = center + box.getDelta();
AxialBox worldBox(min,max);
return YawedBox(worldBox,yaw);
}
// ----------
// Rotate-translate methods
Sphere transform_rt ( Sphere const & sphere, Transform const & t )
{
Vector center = t.rotateTranslate_l2p( sphere.getCenter() );
return Sphere(center, sphere.getRadius());
}
OrientedCylinder transform_rt ( Cylinder const & cyl, Transform const & t )
{
Vector base = t.rotateTranslate_l2p(cyl.getBase());
Vector axis = t.rotate_l2p( Vector::unitY );
return OrientedCylinder ( base, axis, cyl.getRadius(), cyl.getHeight() );
}
OrientedCylinder transform_rt ( OrientedCylinder const & cyl, Transform const & t )
{
Vector base = t.rotateTranslate_l2p(cyl.getBase());
Vector axis = t.rotate_l2p(cyl.getAxis());
return OrientedCylinder ( base, axis, cyl.getRadius(), cyl.getHeight() );
}
OrientedBox transform_rt ( AxialBox const & box, Transform const & t )
{
Vector delta = box.getDelta();
Vector center = t.rotateTranslate_l2p(box.getCenter());
Vector xAxis = t.rotate_l2p( Vector::unitX );
Vector yAxis = t.rotate_l2p( Vector::unitY );
Vector zAxis = t.rotate_l2p( Vector::unitZ );
Vector worldCenter = t.rotateTranslate_l2p( center );
OrientedBox temp( worldCenter, xAxis, yAxis, zAxis, delta.x, delta.y, delta.z );
return temp;
}
// ----------
Sphere scale ( Sphere const & sphere, float scaleFactor )
{
return Sphere( sphere.getCenter() * scaleFactor,
sphere.getRadius() * scaleFactor );
}
Cylinder scale ( Cylinder const & cylinder, float scaleFactor )
{
return Cylinder( cylinder.getBase() * scaleFactor,
cylinder.getRadius() * scaleFactor,
cylinder.getHeight() * scaleFactor );
}
OrientedCylinder scale ( OrientedCylinder const & cylinder, float scaleFactor )
{
return OrientedCylinder( cylinder.getBase() * scaleFactor,
cylinder.getAxis(),
cylinder.getRadius() * scaleFactor,
cylinder.getHeight() * scaleFactor );
}
AxialBox scale ( AxialBox const & box, float scaleFactor )
{
return AxialBox( box.getMin() * scaleFactor,
box.getMax() * scaleFactor );
}
YawedBox scale ( YawedBox const & box, float scaleFactor )
{
return YawedBox( box.getBase() * scaleFactor,
box.getAxisX(),
box.getAxisZ(),
box.getExtentX() * scaleFactor,
box.getExtentZ() * scaleFactor,
box.getHeight() * scaleFactor );
}
OrientedBox scale ( OrientedBox const & box, float scaleFactor )
{
return OrientedBox( box.getCenter() * scaleFactor,
box.getAxisX(),
box.getAxisY(),
box.getAxisZ(),
box.getExtentX() * scaleFactor,
box.getExtentY() * scaleFactor,
box.getExtentZ() * scaleFactor );
}
// ----------------------------------------------------------------------
AxialBox inflate ( AxialBox const & box, float amount )
{
return AxialBox( box.getMax() + Vector(amount,amount,amount), box.getMin() - Vector(amount,amount,amount) );
}
Sphere inflate ( Sphere const & sphere, float amount )
{
return Sphere( sphere.getCenter(), sphere.getRadius() + amount );
}
Cylinder inflate ( Cylinder const & cylinder, float amount )
{
return Cylinder ( cylinder.getBase() - Vector(0.0f,amount,0.0f), cylinder.getRadius() + amount, cylinder.getHeight() + amount * 2.0f );
}
// ----------------------------------------------------------------------
} // namespace ShapeUtils
@@ -0,0 +1,119 @@
// ======================================================================
//
// ShapeUtils.h
// copyright (c) 2001 Sony Online Entertainment
//
// ----------------------------------------------------------------------
#ifndef INCLUDED_ShapeUtils_H
#define INCLUDED_ShapeUtils_H
class Transform;
class Vector;
class MultiShape;
class Sphere;
class Cylinder;
class OrientedCylinder;
class AxialBox;
class YawedBox;
class OrientedBox;
class Segment3d;
class Line3d;
// ----------------------------------------------------------------------
namespace ShapeUtils
{
// ----------
// Transform the given shape to parent space and enclose it with another shape
AxialBox EncloseTransform_ABox ( AxialBox const & box, Transform const & tform );
// ----------
MultiShape transform ( MultiShape const & shape,
Transform const & tform,
float scaleFactor = 1.0f );
Sphere transform ( Sphere const & sphere,
Transform const & tform,
float scaleFactor = 1.0f );
Cylinder transform ( Cylinder const & cylinder,
Transform const & tform,
float scaleFactor = 1.0f );
OrientedCylinder transform ( OrientedCylinder const & cylinder,
Transform const & tform,
float scaleFactor = 1.0f );
// This will produce the smallest axis-aligned bounding box containing the transformed box
AxialBox transform ( AxialBox const & box,
Transform const & tform,
float scaleFactor = 1.0f );
// ----------------------------------------------------------------------
Segment3d transform_p2l ( Segment3d const & seg,
Transform const & tform,
float scaleFactor = 1.0f );
Line3d transform_p2l ( Line3d const & line,
Transform const & tform,
float scaleFactor = 1.0f );
// ----------------------------------------------------------------------
// Transform-shape-to-world methods
// Translate-only methods
Sphere translate ( Sphere const & sphere, Vector const & t );
Cylinder translate ( Cylinder const & cyl, Vector const & t );
AxialBox translate ( AxialBox const & box, Vector const & t );
MultiShape translate ( MultiShape const & shape, Vector const & t );
Sphere transform_t ( Sphere const & sphere, Transform const & t );
Cylinder transform_t ( Cylinder const & cyl, Transform const & t );
AxialBox transform_t ( AxialBox const & box, Transform const & t );
// ----------
// Yaw-translate methods
Sphere transform_yt ( Sphere const & sphere, Transform const & t );
Cylinder transform_yt ( Cylinder const & cyl, Transform const & t );
YawedBox transform_yt ( AxialBox const & box, Transform const & t );
// ----------
// Rotate-translate methods
Sphere transform_rt ( Sphere const & sphere, Transform const & t );
OrientedCylinder transform_rt ( Cylinder const & cyl, Transform const & t );
OrientedCylinder transform_rt ( OrientedCylinder const & cyl, Transform const & t );
OrientedBox transform_rt ( AxialBox const & box, Transform const & t );
// ----------
Sphere scale ( Sphere const & sphere, float scaleFactor );
Cylinder scale ( Cylinder const & cylinder, float scaleFactor );
OrientedCylinder scale ( OrientedCylinder const & cylinder, float scaleFactor );
AxialBox scale ( AxialBox const & box, float scaleFactor );
YawedBox scale ( YawedBox const & box, float scaleFactor );
OrientedBox scale ( OrientedBox const & box, float scaleFactor );
// ----------
// Other useful methods
AxialBox inflate ( AxialBox const & B, float amount );
Sphere inflate ( Sphere const & S, float amount );
Cylinder inflate ( Cylinder const & C, float amount );
}; // namespace ShapeUtils
// ======================================================================
#endif // #ifndef INCLUDED_ShapeUtils_H
@@ -0,0 +1,42 @@
// ======================================================================
//
// Torus.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Torus.h"
Vector Torus::transformToLocal( Vector const & V ) const
{
return rotateToLocal( V - m_center );
}
Vector Torus::transformToWorld ( Vector const & V ) const
{
return rotateToWorld(V) + m_center;
}
Vector Torus::rotateToLocal ( Vector const & V ) const
{
Vector temp;
temp.x = V.dot(m_tangent);
temp.y = V.dot(m_axis);
temp.z = V.dot(m_binormal);
return temp;
}
Vector Torus::rotateToWorld ( Vector const & V ) const
{
Vector temp = Vector::zero;
temp += m_tangent * V.x;
temp += m_axis * V.y;
temp += m_binormal * V.z;
return temp;
}
@@ -0,0 +1,103 @@
// ======================================================================
//
// Torus.h
// copyright (c) 2001 Sony Online Entertainment
//
// Simple class to represent a 2D Torus in the X-Z plane
//
// ----------------------------------------------------------------------
#ifndef INCLUDED_Torus_H
#define INCLUDED_Torus_H
#include "sharedMath/Vector.h"
// ======================================================================
class Torus
{
public:
Torus ( Vector const & center, float majorRadius, float minorRadius );
Torus ( Vector const & center, Vector const & axis, float majorRadius, float minorRadius );
// ----------
Vector const & getCenter ( void ) const;
Vector const & getAxis ( void ) const;
float getMajorRadius ( void ) const;
float getMinorRadius ( void ) const;
Vector transformToLocal ( Vector const & V ) const;
Vector transformToWorld ( Vector const & V ) const;
Vector rotateToLocal ( Vector const & V ) const;
Vector rotateToWorld ( Vector const & V ) const;
bool isOriented ( void ) const;
protected:
Vector m_center;
Vector m_axis;
Vector m_tangent;
Vector m_binormal;
float m_majorRadius;
float m_minorRadius;
};
// ----------------------------------------------------------------------
inline Torus::Torus ( Vector const & center, float majorRadius, float minorRadius )
: m_center(center),
m_axis(0,1,0),
m_tangent(1,0,0),
m_binormal(0,0,1),
m_majorRadius(majorRadius),
m_minorRadius(minorRadius)
{
}
inline Torus::Torus ( Vector const & center, Vector const & axis, float majorRadius, float minorRadius )
: m_center(center),
m_axis(axis),
m_majorRadius(majorRadius),
m_minorRadius(minorRadius)
{
m_tangent = m_axis.cross(Vector(0,0,1));
m_binormal = m_tangent.cross(m_axis);
}
inline Vector const & Torus::getCenter ( void ) const
{
return m_center;
}
inline Vector const & Torus::getAxis ( void ) const
{
return m_axis;
}
inline float Torus::getMajorRadius ( void ) const
{
return m_majorRadius;
}
inline float Torus::getMinorRadius ( void ) const
{
return m_minorRadius;
}
inline bool Torus::isOriented ( void ) const
{
return fabs(m_axis.y - 1.0f) > 0.00001f;
}
// ----------------------------------------------------------------------
#endif
@@ -0,0 +1,10 @@
// ======================================================================
//
// Triangle2d.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
//#include "sharedMath/Triangle2d.h"
@@ -0,0 +1,102 @@
// ======================================================================
//
// Triangle2d.h
// copyright (c) 2001 Sony Online Entertainment
//
// ----------------------------------------------------------------------
#ifndef INCLUDED_Triangle2d_H
#define INCLUDED_Triangle2d_H
#include "sharedMath/Vector2d.h"
// ======================================================================
// 2d Triangle
class Triangle2d
{
public:
Triangle2d( Vector2d const & a, Vector2d const & b, Vector2d const & c );
Triangle2d();
// ----------
Vector2d const & getCorner ( int i ) const;
void setCorner ( int i, Vector2d const & newCorner );
Vector2d const & getCornerA ( void ) const;
Vector2d const & getCornerB ( void ) const;
Vector2d const & getCornerC ( void ) const;
void setCornerA ( Vector2d const & newCorner );
void setCornerB ( Vector2d const & newCorner );
void setCornerC ( Vector2d const & newCorner );
// ----------
protected:
Vector2d m_cornerA;
Vector2d m_cornerB;
Vector2d m_cornerC;
};
// ----------
inline Triangle2d::Triangle2d( Vector2d const & a, Vector2d const & b, Vector2d const & c )
{
m_cornerA = a;
m_cornerB = b;
m_cornerC = c;
}
inline Triangle2d::Triangle2d()
{
}
inline Vector2d const & Triangle2d::getCorner ( int i ) const
{
return (&m_cornerA)[i % 3];
}
inline void Triangle2d::setCorner( int i, Vector2d const & newCorner )
{
(&m_cornerA)[i%3] = newCorner;
}
inline Vector2d const & Triangle2d::getCornerA ( void ) const
{
return m_cornerA;
}
inline Vector2d const & Triangle2d::getCornerB ( void ) const
{
return m_cornerB;
}
inline Vector2d const & Triangle2d::getCornerC ( void ) const
{
return m_cornerC;
}
inline void Triangle2d::setCornerA ( Vector2d const & newCorner )
{
m_cornerA = newCorner;
}
inline void Triangle2d::setCornerB ( Vector2d const & newCorner )
{
m_cornerB = newCorner;
}
inline void Triangle2d::setCornerC ( Vector2d const & newCorner )
{
m_cornerC = newCorner;
}
// ----------------------------------------------------------------------
#endif // #ifdef INCLUDED_Triangle2d_H

Some files were not shown because too many files have changed in this diff Show More