mirror of
https://bitbucket.org/theswgsource/src-1.2.git
synced 2026-07-31 01:15:48 -04:00
Added sharedMath and sharedRandom libraries
This commit is contained in:
@@ -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 ¢er, real radius);
|
||||
Sphere(real x, real y, real z, real radius);
|
||||
|
||||
void setCenter(real x, real y, real z);
|
||||
void setCenter(const Vector ¢er);
|
||||
void setRadius(real radius);
|
||||
void set(const Vector ¢er, 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 ¢er, 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 ¢er)
|
||||
{
|
||||
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 ¢er, 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 ¢er);
|
||||
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 ¢er = 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 ¢er = 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
Reference in New Issue
Block a user