Added sharedMath and sharedRandom libraries

This commit is contained in:
Anonymous
2014-01-14 02:05:25 -07:00
parent 377fab52c5
commit a4f2c06f77
187 changed files with 21231 additions and 1 deletions
+2
View File
@@ -3,7 +3,9 @@ add_subdirectory(sharedDebug)
add_subdirectory(sharedFile)
add_subdirectory(sharedFoundation)
add_subdirectory(sharedFoundationTypes)
add_subdirectory(sharedMath)
add_subdirectory(sharedMemoryManager)
add_subdirectory(sharedNetworkMessages)
add_subdirectory(sharedRandom)
add_subdirectory(sharedSynchronization)
add_subdirectory(sharedThread)
@@ -65,7 +65,7 @@ include_directories(
${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_ROOT_SOURCE_DIR}/external/3rd/library/vtune
${SWG_EXTERNALS_SOURCE_DIR}/3rd/library/vtune
)
add_library(sharedDebug STATIC
@@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 2.8)
project(sharedMath)
if(WIN32)
add_definitions(/D_CRT_SECURE_NO_WARNINGS)
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/public)
add_subdirectory(src)
@@ -0,0 +1 @@
#include "../../src/shared/core/AxialBox.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/Capsule.h"
@@ -0,0 +1 @@
#include "../../src/shared/CatmullRomSpline.h"
@@ -0,0 +1,2 @@
#include "../../src/shared/core/Circle.h"
@@ -0,0 +1 @@
#include "../../src/shared/CompressedQuaternion.h"
@@ -0,0 +1 @@
#include "../../src/shared/ConfigSharedMath.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/Cylinder.h"
@@ -0,0 +1 @@
#include "../../src/shared/debug/DebugShapeRenderer.h"
@@ -0,0 +1 @@
#include "../../src/shared/FirstSharedMath.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/Hsv.h"
@@ -0,0 +1 @@
#include "../../src/shared/IndexedTriangleList.h"
@@ -0,0 +1 @@
#include "../../src/shared/Line2d.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/Line3d.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/MultiShape.h"
@@ -0,0 +1 @@
#include "../../src/shared/MxCifQuadTree.h"
@@ -0,0 +1 @@
#include "../../src/shared/MxCifQuadTreeBounds.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/OrientedBox.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/OrientedCircle.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/OrientedCylinder.h"
@@ -0,0 +1 @@
#include "../../src/shared/PackedArgb.h"
@@ -0,0 +1 @@
#include "../../src/shared/PackedRgb.h"
@@ -0,0 +1 @@
#include "../../src/shared/PaletteArgb.h"
@@ -0,0 +1 @@
#include "../../src/shared/PaletteArgbList.h"
@@ -0,0 +1 @@
#include "../../src/shared/Plane.h"
@@ -0,0 +1,2 @@
#include "../../src/shared/core/Plane3d.h"
@@ -0,0 +1 @@
#include "../../src/shared/PolySolver.h"
@@ -0,0 +1 @@
#include "../../src/shared/PositionVertexIndexer.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/Quadratic.h"
@@ -0,0 +1 @@
#include "../../src/shared/Quaternion.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/Range.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/RangeLoop.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/Ray3d.h"
@@ -0,0 +1 @@
#include "../../src/shared/Rectangle2d.h"
@@ -0,0 +1,2 @@
#include "../../src/shared/core/Ribbon3d.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/Ring.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/Segment3d.h"
@@ -0,0 +1 @@
#include "../../src/shared/SetupSharedMath.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/ShapeUtils.h"
@@ -0,0 +1 @@
#include "../../src/shared/SpatialSubdivision.h"
@@ -0,0 +1 @@
#include "../../src/shared/Sphere.h"
@@ -0,0 +1 @@
#include "../../src/shared/SphereTree.h"
@@ -0,0 +1 @@
#include "../../src/shared/SphereTreeNode.h"
@@ -0,0 +1,5 @@
#if defined(PLATFORM_WIN32)
#include "../../src/win32/SseMath.h"
#else
#error unsupported platform
#endif
@@ -0,0 +1 @@
#include "../../src/shared/core/Torus.h"
@@ -0,0 +1 @@
#include "../../src/shared/Transform.h"
@@ -0,0 +1 @@
#include "../../src/shared/Transform2d.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/Triangle2d.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/Triangle3d.h"
@@ -0,0 +1 @@
#include "../../src/shared/Vector.h"
@@ -0,0 +1 @@
#include "../../src/shared/Vector2d.h"
@@ -0,0 +1 @@
#include "../../src/shared/VectorArgb.h"
@@ -0,0 +1 @@
#include "../../src/shared/VectorRgba.h"
@@ -0,0 +1 @@
#include "../../src/shared/Volume.h"
@@ -0,0 +1 @@
#include "../../src/shared/WaveForm.h"
@@ -0,0 +1 @@
#include "../../src/shared/WaveForm3D.h"
@@ -0,0 +1 @@
#include "../../src/shared/core/YawedBox.h"
@@ -0,0 +1,133 @@
set(SHARED_SOURCES
shared/CatmullRomSpline.cpp
shared/CatmullRomSpline.h
shared/CompressedQuaternion.cpp
shared/CompressedQuaternion.h
shared/ConfigSharedMath.cpp
shared/ConfigSharedMath.h
shared/FirstSharedMath.h
shared/IndexedTriangleList.cpp
shared/IndexedTriangleList.h
shared/Line2d.h
shared/MxCifQuadTree.cpp
shared/MxCifQuadTree.h
shared/MxCifQuadTreeBounds.cpp
shared/MxCifQuadTreeBounds.h
shared/PackedArgb.cpp
shared/PackedArgb.h
shared/PackedRgb.cpp
shared/PackedRgb.h
shared/PaletteArgb.cpp
shared/PaletteArgb.h
shared/PaletteArgbList.cpp
shared/PaletteArgbList.h
shared/Plane.cpp
shared/Plane.h
shared/PolySolver.cpp
shared/PolySolver.h
shared/Quaternion.cpp
shared/Quaternion.h
shared/Rectangle2d.cpp
shared/Rectangle2d.h
shared/SetupSharedMath.cpp
shared/SetupSharedMath.h
shared/SpatialSubdivision.cpp
shared/SpatialSubdivision.h
shared/Sphere.cpp
shared/Sphere.h
shared/SphereTree.h
shared/SphereTreeNode.h
shared/Transform.cpp
shared/Transform.h
shared/Transform2d.cpp
shared/Transform2d.h
shared/Vector.cpp
shared/Vector.h
shared/Vector2d.h
shared/VectorArgb.cpp
shared/VectorArgb.h
shared/Volume.cpp
shared/Volume.h
shared/WaveForm.cpp
shared/WaveForm.h
shared/WaveForm3D.cpp
shared/WaveForm3D.h
shared/core/AxialBox.cpp
shared/core/AxialBox.h
shared/core/Capsule.cpp
shared/core/Capsule.h
shared/core/Circle.cpp
shared/core/Circle.h
shared/core/Cylinder.cpp
shared/core/Cylinder.h
shared/core/Line3d.cpp
shared/core/Line3d.h
shared/core/MultiShape.cpp
shared/core/MultiShape.h
shared/core/OrientedBox.cpp
shared/core/OrientedBox.h
shared/core/OrientedCircle.cpp
shared/core/OrientedCircle.h
shared/core/OrientedCylinder.cpp
shared/core/OrientedCylinder.h
shared/core/Plane3d.cpp
shared/core/Plane3d.h
shared/core/Quadratic.cpp
shared/core/Quadratic.h
shared/core/Range.cpp
shared/core/Range.h
shared/core/RangeLoop.cpp
shared/core/RangeLoop.h
shared/core/Ray3d.cpp
shared/core/Ray3d.h
shared/core/Ribbon3d.cpp
shared/core/Ribbon3d.h
shared/core/Ring.cpp
shared/core/Ring.h
shared/core/Segment3d.cpp
shared/core/Segment3d.h
shared/core/ShapeUtils.cpp
shared/core/ShapeUtils.h
shared/core/Torus.cpp
shared/core/Torus.h
shared/core/Triangle2d.cpp
shared/core/Triangle2d.h
shared/core/Triangle3d.cpp
shared/core/Triangle3d.h
shared/core/YawedBox.cpp
shared/core/YawedBox.h
shared/debug/DebugShapeRenderer.cpp
shared/debug/DebugShapeRenderer.h
)
if(WIN32)
set(PLATFORM_SOURCES
win32/FirstSharedMath.cpp
win32/SseMath.cpp
win32/SseMath.h
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/win32)
else()
set(PLATFORM_SOURCES "")
endif()
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/shared
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedDebug/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFile/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundation/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundationTypes/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMemoryManager/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedRandom/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedSynchronization/include/public
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/fileInterface/include/public
)
add_library(sharedMath STATIC
${SHARED_SOURCES}
${PLATFORM_SOURCES}
)
@@ -0,0 +1,42 @@
// ============================================================================
//
// CatmullRomSpline.cpp
// Copyright Sony Online Entertainment
//
// ============================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/CatmullRomSpline.h"
#include "sharedMath/Vector.h"
//-----------------------------------------------------------------------------
void CatmullRomSpline::getCatmullRomSplinePoint(float const c1x, float const c1y, float const c2x, float const c2y, float const c3x, float const c3y, float const c4x, float const c4y, float const t, float &resultX, float &resultY)
{
float const t3 = t * t * t;
float const t2 = t * t;
float const a = (-0.5f * t3 + t2 - 0.5f * t);
float const b = (1.5f * t3 - 2.5f * t2 + 1.0f);
float const c = (-1.5f * t3 + 2.0f * t2 + 0.5f * t);
float const d = (0.5f * t3 - 0.5f * t2);
resultX = c1x * a + c2x * b + c3x * c + c4x * d;
resultY = c1y * a + c2y * b + c3y * c + c4y * d;
}
//-----------------------------------------------------------------------------
void CatmullRomSpline::getCatmullRomSplinePoint3d(Vector const &c1, Vector const &c2, Vector const &c3, Vector const &c4, float const t, Vector &result)
{
float const t3 = t * t * t;
float const t2 = t * t;
float const a = (-0.5f * t3 + t2 - 0.5f * t);
float const b = (1.5f * t3 - 2.5f * t2 + 1.0f);
float const c = (-1.5f * t3 + 2.0f * t2 + 0.5f * t);
float const d = (0.5f * t3 - 0.5f * t2);
result.x = c1.x * a + c2.x * b + c3.x * c + c4.x * d;
result.y = c1.y * a + c2.y * b + c3.y * c + c4.y * d;
result.z = c1.z * a + c2.z * b + c3.z * c + c4.z * d;
}
// ============================================================================
@@ -0,0 +1,33 @@
// ============================================================================
//
// CatmullRomSpline.h
// Copyright Sony Online Entertainment
//
// ============================================================================
#ifndef INCLUDED_CatmullRomSpline_H
#define INCLUDED_CatmullRomSpline_H
class Vector;
//-----------------------------------------------------------------------------
class CatmullRomSpline
{
public:
static void getCatmullRomSplinePoint(float const c1x, float const c1y, float const c2x, float const c2y, float const c3x, float const c3y, float const c4x, float const c4y, float const t, float &resultX, float &resultY);
static void getCatmullRomSplinePoint3d(Vector const &c1, Vector const &c2, Vector const &c3, Vector const &c4, float const t, Vector &result);
private:
// Disabled
CatmullRomSpline();
CatmullRomSpline(CatmullRomSpline const &);
~CatmullRomSpline();
CatmullRomSpline &operator =(CatmullRomSpline const &);
};
// ============================================================================
#endif // INCLUDED_CatmullRomSpline_H
@@ -0,0 +1,637 @@
// ======================================================================
//
// CompressedQuaternion.cpp
// Copyright 2002 Sony Online Entertainment, Inc.
// All Rights Reserved.
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/CompressedQuaternion.h"
#include "sharedMath/Quaternion.h"
#include <limits>
#include <vector>
// ======================================================================
#if DEBUG_LEVEL == DEBUG_LEVEL_DEBUG
#define VERIFY_COMPRESSION 1
#else
#define VERIFY_COMPRESSION 0
#endif
// ======================================================================
namespace CompressedQuaternionNamespace
{
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
struct FormatPrecisionInfo
{
//-- Specified directly.
uint8 formatId;
uint8 baseIndexMask;
int baseCount;
float baseSeparation;
//-- Calculated.
float compressFactorElevenBit;
float expandFactorElevenBit;
float compressFactorTenBit;
float expandFactorTenBit;
};
#define MAKE_BASE_SEPARATION(baseShiftCount) (2.0f / static_cast<float>((0x01 << (baseShiftCount)) + 1))
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class FormatData
{
public:
FormatData();
void install(float baseValue, uint8 formatPrecisionIndex);
uint32 compressTenBit(float uncompressedValue) const;
uint32 compressElevenBit(float uncompressedValue) const;
float expandTenBit(uint32 compressedValue) const;
float expandElevenBit(uint32 compressedValue) const;
private:
float m_baseValue;
uint8 m_formatPrecisionIndex;
#ifdef _DEBUG
bool m_installed;
#endif
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// packed format: [MSB] x-11-bit y-11-bit z-10-bit
const uint32 cs_xShift = 21;
const uint32 cs_yShift = 10;
// Acceptable error in given w calculation from real w calculation.
const float cs_xAcceptableEpsilon = 0.001f;
const float cs_yAcceptableEpsilon = 0.001f;
const float cs_zAcceptableEpsilon = 2.0f * cs_xAcceptableEpsilon;
const float cs_wAcceptableEpsilon = 0.1f;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// 11-bit compressed format
const uint32 cs_valueMaskElevenBit = BINARY3(0011, 1111, 1111);
const uint32 cs_signBitElevenBit = BINARY3(0100, 0000, 0000);
// 10-bit compressed format
const uint32 cs_valueMaskTenBit = BINARY3(0001, 1111, 1111);
const uint32 cs_signBitTenBit = BINARY3(0010, 0000, 0000);
const int cs_minFormatValue = 0;
const int cs_maxFormatValue = 254;
#define MAKE_PRECISION_INFO(formatId, baseIndexMask, baseShiftCount) {formatId, baseIndexMask, 0x01 << baseShiftCount, MAKE_BASE_SEPARATION(baseShiftCount), 0.0f, 0.0f, 0.0f, 0.0f}
FormatPrecisionInfo s_formatPrecisionInfo[] =
{
MAKE_PRECISION_INFO(BINARY2(1111, 1110), BINARY2(0000, 0000), 0),
MAKE_PRECISION_INFO(BINARY2(1111, 1100), BINARY2(0000, 0001), 1),
MAKE_PRECISION_INFO(BINARY2(1111, 1000), BINARY2(0000, 0011), 2),
MAKE_PRECISION_INFO(BINARY2(1111, 0000), BINARY2(0000, 0111), 3),
MAKE_PRECISION_INFO(BINARY2(1110, 0000), BINARY2(0000, 1111), 4),
MAKE_PRECISION_INFO(BINARY2(1100, 0000), BINARY2(0001, 1111), 5),
MAKE_PRECISION_INFO(BINARY2(1000, 0000), BINARY2(0011, 1111), 6)
};
const int cs_minBaseShiftCount = 0;
const int cs_maxBaseShiftCount = static_cast<int>(sizeof(s_formatPrecisionInfo) / sizeof(s_formatPrecisionInfo[0])) - 1;
FormatData s_formatData[cs_maxFormatValue + 1];
bool s_installed;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int convertShiftToCount(int shift);
float calculateRange(int baseShiftCount);
void findClosestBase(int baseShiftCount, float midpoint, int &baseIndex, float &baseValue);
int findBaseShiftCountCoveringRange(float range);
bool findFormatForRange(int baseShiftCount, float minValue, float maxValue, uint8 &format);
uint32 doCompress(float w, float x, float y, float z, uint8 xFormat, uint8 yFormat, uint8 zFormat);
void doExpand(uint32 data, uint8 xFormat, uint8 yFormat, uint8 zFormat, float &w, float &x, float &y, float &z);
}
using namespace CompressedQuaternionNamespace;
// ======================================================================
// class CompressedQuaternionNamespace::FormatData
// ======================================================================
CompressedQuaternionNamespace::FormatData::FormatData() :
m_baseValue(0),
m_formatPrecisionIndex(0)
#ifdef _DEBUG
, m_installed(false)
#endif
{
}
// ----------------------------------------------------------------------
void CompressedQuaternionNamespace::FormatData::install(float baseValue, uint8 formatPrecisionIndex)
{
VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(cs_minBaseShiftCount, static_cast<int>(formatPrecisionIndex), cs_maxBaseShiftCount);
m_baseValue = baseValue;
m_formatPrecisionIndex = formatPrecisionIndex;
#ifdef _DEBUG
m_installed = true;
#endif
}
// ----------------------------------------------------------------------
uint32 CompressedQuaternionNamespace::FormatData::compressTenBit(float uncompressedValue) const
{
DEBUG_FATAL(!m_installed, ("format not installed."));
if (uncompressedValue >= m_baseValue)
{
const uint32 rawValue = static_cast<uint32>(s_formatPrecisionInfo[m_formatPrecisionIndex].compressFactorTenBit * std::max(0.0f, uncompressedValue - m_baseValue));
return std::min(cs_valueMaskTenBit, rawValue);
}
else
{
const uint32 rawValue = static_cast<uint32>(s_formatPrecisionInfo[m_formatPrecisionIndex].compressFactorTenBit * std::max(0.0f, m_baseValue - uncompressedValue));
return cs_signBitTenBit | std::min(cs_valueMaskTenBit, rawValue);
}
}
// ----------------------------------------------------------------------
uint32 CompressedQuaternionNamespace::FormatData::compressElevenBit(float uncompressedValue) const
{
DEBUG_FATAL(!m_installed, ("format not installed."));
if (uncompressedValue >= m_baseValue)
{
const uint32 rawValue = static_cast<uint32>(s_formatPrecisionInfo[m_formatPrecisionIndex].compressFactorElevenBit * std::max(0.0f, uncompressedValue - m_baseValue));
return std::min(cs_valueMaskElevenBit, rawValue);
}
else
{
const uint32 rawValue = static_cast<uint32>(s_formatPrecisionInfo[m_formatPrecisionIndex].compressFactorElevenBit * std::max(0.0f, m_baseValue - uncompressedValue));
return cs_signBitElevenBit | std::min(cs_valueMaskElevenBit, rawValue);
}
}
// ----------------------------------------------------------------------
// This function works properly with any kind of junk outside the lowest 10 bits. You do not need to mask the parameter prior to calling.
float CompressedQuaternionNamespace::FormatData::expandTenBit(uint32 compressedValue) const
{
DEBUG_FATAL(!m_installed, ("format not installed."));
if ((compressedValue & cs_signBitTenBit) != 0)
return m_baseValue - (static_cast<float>(compressedValue & cs_valueMaskTenBit) * s_formatPrecisionInfo[m_formatPrecisionIndex].expandFactorTenBit);
else
return m_baseValue + (static_cast<float>(compressedValue & cs_valueMaskTenBit) * s_formatPrecisionInfo[m_formatPrecisionIndex].expandFactorTenBit);
}
// ----------------------------------------------------------------------
// This function works properly with any kind of junk outside the lowest 11 bits. You do not need to mask the parameter prior to calling.
float CompressedQuaternionNamespace::FormatData::expandElevenBit(uint32 compressedValue) const
{
DEBUG_FATAL(!m_installed, ("format not installed."));
if ((compressedValue & cs_signBitElevenBit) != 0)
return m_baseValue - (static_cast<float>(compressedValue & cs_valueMaskElevenBit) * s_formatPrecisionInfo[m_formatPrecisionIndex].expandFactorElevenBit);
else
return m_baseValue + (static_cast<float>(compressedValue & cs_valueMaskElevenBit) * s_formatPrecisionInfo[m_formatPrecisionIndex].expandFactorElevenBit);
}
// ======================================================================
inline int CompressedQuaternionNamespace::convertShiftToCount(int shift)
{
VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, shift, 31);
return (0x01 << static_cast<uint8>(shift));
}
// ----------------------------------------------------------------------
inline float CompressedQuaternionNamespace::calculateRange(int baseShiftCount)
{
DEBUG_FATAL(baseShiftCount < 0, ("bad baseShiftCount arg [%d].", baseShiftCount));
return 4.0f / static_cast<float>(convertShiftToCount(baseShiftCount) + 1);
}
// ----------------------------------------------------------------------
void CompressedQuaternionNamespace::findClosestBase(int baseShiftCount, float midpoint, int &baseIndex, float &baseValue)
{
VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(cs_minBaseShiftCount, baseShiftCount, cs_maxBaseShiftCount);
//-- Brute force, this could be far more intelligent.
const int baseCount = s_formatPrecisionInfo[baseShiftCount].baseCount;
const float baseSeparation = s_formatPrecisionInfo[baseShiftCount].baseSeparation;
float closestBaseDistance = std::numeric_limits<float>::max();
float closestBaseValue = std::numeric_limits<float>::max();
int closestBaseIndex = -1;
for (int testBaseIndex = 0; testBaseIndex < baseCount; ++testBaseIndex)
{
const float testBaseValue = -1.0f + (testBaseIndex + 1) * baseSeparation;
const float testDistance = abs(testBaseValue - midpoint);
if (testDistance < closestBaseDistance)
{
closestBaseDistance = testDistance;
closestBaseValue = testBaseValue;
closestBaseIndex = testBaseIndex;
}
else
{
//-- We're getting farther away, stop now.
break;
}
}
baseIndex = closestBaseIndex;
baseValue = closestBaseValue;
}
// ----------------------------------------------------------------------
int CompressedQuaternionNamespace::findBaseShiftCountCoveringRange(float range)
{
for (int baseShiftCount = cs_maxBaseShiftCount; baseShiftCount >= 0; --baseShiftCount)
{
const float baseCountRange = calculateRange(baseShiftCount);
if (baseCountRange >= range)
{
//-- We found the tightest-fitting base count that is at least large enough to handle the specified range.
// We do this so that we have the greatest precision available over that tightest-fitting range.
return baseShiftCount;
}
}
DEBUG_FATAL(true, ("Failed to find a base count that handles the range [%g].", range));
return -1; //lint !e527 // unreachable // reachable in release.
}
// ----------------------------------------------------------------------
bool CompressedQuaternionNamespace::findFormatForRange(int baseShiftCount, float minValue, float maxValue, uint8 &format)
{
VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(cs_minBaseShiftCount, baseShiftCount, cs_maxBaseShiftCount);
DEBUG_FATAL(minValue > maxValue, ("minValue [%g] > maxValue [%g].", minValue, maxValue));
//-- Find the user range and midpoint.
const float range = maxValue - minValue;
const float midpoint = minValue + 0.5f * range;
//-- Find this format's closest base to the midpoint.
int baseIndex = -1;
float baseValue = 0.0f;
findClosestBase(baseShiftCount, midpoint, baseIndex, baseValue);
//-- Check if the user range fits within this format's base and range.
const float formatHalfRange = 0.5f * calculateRange(baseShiftCount);
const bool userRangeFitFormat = ((minValue >= (baseValue - formatHalfRange)) && (maxValue <= (baseValue + formatHalfRange)));
if (!userRangeFitFormat)
return false;
//-- Compute the format value from this information.
DEBUG_FATAL(static_cast<int>(s_formatPrecisionInfo[baseShiftCount].baseIndexMask & static_cast<uint8>(baseIndex)) != baseIndex, ("base index %d not valid for format with baseShift = %d.", baseIndex, baseShiftCount));
format = static_cast<uint8>(s_formatPrecisionInfo[baseShiftCount].formatId | static_cast<uint8>(baseIndex));
return true;
}
// ----------------------------------------------------------------------
uint32 CompressedQuaternionNamespace::doCompress(float w, float x, float y, float z, uint8 xFormat, uint8 yFormat, uint8 zFormat)
{
//-- Flip the quaternion if w is negative so we don't need to store a sign bit for w.
if (w < 0.0f)
{
w = -w;
x = -x;
y = -y;
z = -z;
}
//-- Ensure we are compressing a unit quaternion.
VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(-1.0f, x, 1.0f);
VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(-1.0f, y, 1.0f);
VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(-1.0f, z, 1.0f);
#ifdef _DEBUG
// If w is small enough, we won't be able to take the square root.
if (abs(w) >= cs_wAcceptableEpsilon)
{
const float calculatedW = sqrt(1.0f - (x*x + y*y + z*z));
DEBUG_FATAL(!WithinEpsilonInclusive(calculatedW, w, cs_wAcceptableEpsilon), ("Quaternion (w=%g,x=%g,y=%g,z=%g) does not appear to be a unit quaternion.", w, x, y, z));
}
#endif
//-- Pack the values.
const uint32 xPacked = s_formatData[xFormat].compressElevenBit(x);
const uint32 yPacked = s_formatData[yFormat].compressElevenBit(y);
const uint32 zPacked = s_formatData[zFormat].compressTenBit(z);
//-- Shift and combine.
return (xPacked << cs_xShift) | (yPacked << cs_yShift) | zPacked;
}
// ----------------------------------------------------------------------
void CompressedQuaternionNamespace::doExpand(uint32 data, uint8 xFormat, uint8 yFormat, uint8 zFormat, float &w, float &x, float &y, float &z)
{
//-- Expand the components.
x = s_formatData[xFormat].expandElevenBit(data >> cs_xShift);
y = s_formatData[yFormat].expandElevenBit(data >> cs_yShift);
z = s_formatData[zFormat].expandTenBit(data);
//-- Calculate w.
// @todo consider a faster square root approximation function.
w = sqrt(1.0f - (x*x + y*y + z*z));
}
// ======================================================================
// class CompressedQuaternion: static public member functions
// ======================================================================
void CompressedQuaternion::install()
{
//-- Calculate the data for quaternion (de)compression.
for (int baseShiftCount = 0; baseShiftCount <= cs_maxBaseShiftCount; ++baseShiftCount)
{
float const baseSeparation = s_formatPrecisionInfo[baseShiftCount].baseSeparation;
float const halfRange = 0.5f * calculateRange(baseShiftCount);
DEBUG_FATAL(halfRange <= 0.0f, ("bad half range [%g].", halfRange));
// compression factor is : uncompressedUnits * (total compressedUnits/ total uncompressedUnits) = compressedUnits
s_formatPrecisionInfo[baseShiftCount].compressFactorElevenBit = static_cast<float>(BINARY3(0011, 1111, 1111)) / halfRange;
s_formatPrecisionInfo[baseShiftCount].expandFactorElevenBit = halfRange / static_cast<float>(BINARY3(0011, 1111, 1111));
s_formatPrecisionInfo[baseShiftCount].compressFactorTenBit = static_cast<float>(BINARY3(0001, 1111, 1111)) / halfRange;
s_formatPrecisionInfo[baseShiftCount].expandFactorTenBit = halfRange / static_cast<float>(BINARY3(0001, 1111, 1111));
uint8 const formatId = s_formatPrecisionInfo[baseShiftCount].formatId;
int const baseCount = s_formatPrecisionInfo[baseShiftCount].baseCount;
VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, baseCount, cs_maxFormatValue);
for (int i = 0; i < baseCount; ++i)
{
uint8 const formatIndex = static_cast<uint8>(formatId | static_cast<uint8>(i));
float const baseValue = - 1.0f + (i + 1) * baseSeparation;
VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(0, static_cast<int>(formatIndex), cs_maxFormatValue);
s_formatData[formatIndex].install(baseValue, static_cast<uint8>(baseShiftCount));
}
}
s_installed = true;
}
// ----------------------------------------------------------------------
/**
* Determine the most precise compression format for a quaternion component
* that will cover the specified range of value.
*
* Our quaternion compression mechanism uses a fixed number of output bits
* to represent a component of a quaternion. We let the level of precision
* vary based on the range of values that the quaternion component needs to
* represent over time.
*
* The caller should do something like this. For each quaternion component
* that is to be compressed, find the range of values that the component takes
* on across the quaternions that will be compressed with the same compression
* format. Feed the min and max value into this function, then store the
* returned format to be used during compression and decompression for that
* particular component. This needs to be done for the x, y and z components,
* but not the w component. We calculate the w component from the x, y and z.
* We can do this because we are using unit quaternions.
*/
uint8 CompressedQuaternion::getOptimalCompressionFormat(float minValue, float maxValue)
{
DEBUG_FATAL(minValue > maxValue, ("min and max are not set properly."));
//-- Find the largest division count (= highest precision compressed representation)
// that can represent values over the specified range.
int baseShiftCount = findBaseShiftCountCoveringRange(maxValue - minValue);
uint8 format = 255;
for (; (baseShiftCount > -1) && !findFormatForRange(baseShiftCount, minValue, maxValue, format); --baseShiftCount)
{
}
DEBUG_FATAL(baseShiftCount < 0, ("failed to find an encoding for range [%g, %g].", minValue, maxValue));
VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(cs_minFormatValue, static_cast<int>(format), cs_maxFormatValue);
return format;
}
// ----------------------------------------------------------------------
/**
* Find optimal compression format for each x, y and z component of the
* specified source rotations.
*/
void CompressedQuaternion::getOptimalCompressionFormat(const QuaternionVector &sourceRotations, uint8 &xFormat, uint8 &yFormat, uint8 &zFormat)
{
//-- Handle no source rotations.
if (sourceRotations.empty())
{
DEBUG_WARNING(true, ("getOptimalCompressionFormat(): sourceRotations container is empty, returning least precise format."));
// Return least precise format because that is the only thing guaranteed to cover na
xFormat = s_formatPrecisionInfo[0].formatId;
yFormat = s_formatPrecisionInfo[0].formatId;
zFormat = s_formatPrecisionInfo[0].formatId;
return;
}
//-- Collect min and max component values for the rotations.
float minX = std::numeric_limits<float>::max();
float maxX = -std::numeric_limits<float>::max();
float minY = std::numeric_limits<float>::max();
float maxY = -std::numeric_limits<float>::max();
float minZ = std::numeric_limits<float>::max();
float maxZ = -std::numeric_limits<float>::max();
const QuaternionVector::const_iterator endIt = sourceRotations.end();
for (QuaternionVector::const_iterator it = sourceRotations.begin(); it != endIt; ++it)
{
// Get the quaternion.
Quaternion rotation = *it;
// Flip quaternion if w < 0.
if (rotation.w < 0.0f)
{
rotation.x = -rotation.x;
rotation.y = -rotation.y;
rotation.z = -rotation.z;
}
// Update the min and max component values.
minX = std::min(minX, rotation.x);
maxX = std::max(maxX, rotation.x);
minY = std::min(minY, rotation.y);
maxY = std::max(maxY, rotation.y);
minZ = std::min(minZ, rotation.z);
maxZ = std::max(maxZ, rotation.z);
}
xFormat = getOptimalCompressionFormat(minX, maxX);
yFormat = getOptimalCompressionFormat(minY, maxY);
zFormat = getOptimalCompressionFormat(minZ, maxZ);
}
// ----------------------------------------------------------------------
void CompressedQuaternion::compressRotations(const QuaternionVector &sourceRotations, uint8 xFormat, uint8 yFormat, uint8 zFormat, CompressedQuaternionVector &compressedRotations)
{
//-- Adjust destination vector size.
compressedRotations.clear();
compressedRotations.reserve(sourceRotations.size());
//-- Convert each source rotation to a destination rotation.
const QuaternionVector::const_iterator endIt = sourceRotations.end();
for (QuaternionVector::const_iterator it = sourceRotations.begin(); it != endIt; ++it)
{
compressedRotations.push_back(CompressedQuaternion(*it, xFormat, yFormat, zFormat));
#if VERIFY_COMPRESSION
const CompressedQuaternion &compressedRotation = compressedRotations.back();
const Quaternion expandedRotation = compressedRotation.expand(xFormat, yFormat, zFormat);
Quaternion sourceRotation = *it;
if (sourceRotation.w < 0.0f)
{
sourceRotation.w = -sourceRotation.w;
sourceRotation.x = -sourceRotation.x;
sourceRotation.y = -sourceRotation.y;
sourceRotation.z = -sourceRotation.z;
}
const float deltaW = abs(expandedRotation.w - sourceRotation.w);
const float deltaX = abs(expandedRotation.x - sourceRotation.x);
const float deltaY = abs(expandedRotation.y - sourceRotation.y);
const float deltaZ = abs(expandedRotation.z - sourceRotation.z);
if ( (deltaW > cs_wAcceptableEpsilon) ||
(deltaX > cs_xAcceptableEpsilon) ||
(deltaY > cs_yAcceptableEpsilon) ||
(deltaZ > cs_zAcceptableEpsilon))
{
//-- Let's do it again. Make it easier to debug.
const CompressedQuaternion cq2(sourceRotation, xFormat, yFormat, zFormat);
const Quaternion eq2 = cq2.expand(xFormat, yFormat, zFormat);
UNREF(cq2);
UNREF(eq2);
DEBUG_FATAL(true, ("compression data distortion. [source=(%g,%g,%g,%g),dest=(%g,%g,%g,%g)].",
sourceRotation.w, sourceRotation.x, sourceRotation.y, sourceRotation.z,
expandedRotation.w, expandedRotation.x, expandedRotation.y, expandedRotation.z));
}
#endif
}
}
// ======================================================================
CompressedQuaternion::CompressedQuaternion(uint32 compressedValue) :
m_data(compressedValue)
{
}
// ----------------------------------------------------------------------
CompressedQuaternion::CompressedQuaternion(const Quaternion &rhs, uint8 xFormat, uint8 yFormat, uint8 zFormat) :
m_data(doCompress(rhs.w, rhs.x, rhs.y, rhs.z, xFormat, yFormat, zFormat))
{
}
// ----------------------------------------------------------------------
CompressedQuaternion::CompressedQuaternion(float w, float x, float y, float z, uint8 xFormat, uint8 yFormat, uint8 zFormat) :
m_data(doCompress(w, x, y, z, xFormat, yFormat, zFormat))
{
}
// ----------------------------------------------------------------------
Quaternion CompressedQuaternion::expand(uint8 xFormat, uint8 yFormat, uint8 zFormat) const
{
float w;
float x;
float y;
float z;
doExpand(m_data, xFormat, yFormat, zFormat, w, x, y, z);
return Quaternion(w, x, y, z);
}
// ----------------------------------------------------------------------
void CompressedQuaternion::expand(uint8 xFormat, uint8 yFormat, uint8 zFormat, Quaternion &destination) const
{
doExpand(m_data, xFormat, yFormat, zFormat, destination.w, destination.x, destination.y, destination.z);
}
// ----------------------------------------------------------------------
void CompressedQuaternion::expand(uint8 xFormat, uint8 yFormat, uint8 zFormat, float &w, float &x, float &y, float &z) const
{
doExpand(m_data, xFormat, yFormat, zFormat, w, x, y, z);
}
// ----------------------------------------------------------------------
uint32 CompressedQuaternion::getCompressedValue() const
{
return m_data;
}
// ----------------------------------------------------------------------
void CompressedQuaternion::debugDump() const
{
DEBUG_REPORT_LOG(true, ("[data=0x%08x]\n", static_cast<unsigned int>(m_data)));
}
// ======================================================================
@@ -0,0 +1,56 @@
// ======================================================================
//
// CompressedQuaternion.h
// Copyright 2002 Sony Online Entertainment, Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_CompressedQuaternion_H
#define INCLUDED_CompressedQuaternion_H
// ======================================================================
class Quaternion;
// ======================================================================
class CompressedQuaternion
{
public:
typedef stdvector<Quaternion>::fwd QuaternionVector;
typedef stdvector<CompressedQuaternion>::fwd CompressedQuaternionVector;
public:
static void install();
static uint8 getOptimalCompressionFormat(float minValue, float maxValue);
static void getOptimalCompressionFormat(const QuaternionVector &sourceRotations, uint8 &xFormat, uint8 &yFormat, uint8 &zFormat);
static void compressRotations(const QuaternionVector &sourceRotations, uint8 xFormat, uint8 yFormat, uint8 zFormat, CompressedQuaternionVector &compressedRotations);
public:
explicit CompressedQuaternion(uint32 compressedValue);
CompressedQuaternion(const Quaternion &rhs, uint8 xFormat, uint8 yFormat, uint8 zFormat);
CompressedQuaternion(float w, float x, float y, float z, uint8 xFormat, uint8 yFormat, uint8 zFormat);
Quaternion expand(uint8 xFormat, uint8 yFormat, uint8 zFormat) const;
void expand(uint8 xFormat, uint8 yFormat, uint8 zFormat, Quaternion &destination) const;
void expand(uint8 xFormat, uint8 yFormat, uint8 zFormat, float &w, float &x, float &y, float &z) const;
uint32 getCompressedValue() const;
void debugDump() const;
private:
uint32 m_data;
};
// ======================================================================
#endif
@@ -0,0 +1,42 @@
// ======================================================================
//
// ConfigSharedMath.cpp
// copyright 2004 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/ConfigSharedMath.h"
#include "sharedFoundation/ConfigFile.h"
// ======================================================================
#define KEY_BOOL(a,b) (ms_ ## a = ConfigFile::getKeyBool("SharedMath", #a, (b)))
// ======================================================================
namespace ConfigSharedMathNamespace
{
bool ms_reportRangeLoopWarnings;
}
using namespace ConfigSharedMathNamespace;
// ======================================================================
void ConfigSharedMath::install()
{
KEY_BOOL(reportRangeLoopWarnings, false);
}
// ----------------------------------------------------------------------
bool ConfigSharedMath::getReportRangeLoopWarnings()
{
return ms_reportRangeLoopWarnings;
}
// ======================================================================
@@ -0,0 +1,24 @@
// ======================================================================
//
// ConfigSharedMath.h
// Copyright 2004, Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_ConfigSharedMath_H
#define INCLUDED_ConfigSharedMath_H
// ======================================================================
class ConfigSharedMath
{
public:
static void install();
static bool getReportRangeLoopWarnings();
};
// ======================================================================
#endif
@@ -0,0 +1,18 @@
// ======================================================================
//
// FirstMath.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_FirstMath_H
#define INCLUDED_FirstMath_H
// ======================================================================
#include "sharedFoundation/FirstSharedFoundation.h"
// ======================================================================
#endif
@@ -0,0 +1,398 @@
// ======================================================================
//
// IndexedTriangleList.cpp
// Copyright 2001 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/IndexedTriangleList.h"
#include "sharedFile/Iff.h"
#include "sharedMath/Plane.h"
#include "sharedMath/Vector.h"
#include <vector>
#include <limits>
// ======================================================================
const Tag TAG_IDTL = TAG(I,D,T,L);
const Tag TAG_VERT = TAG(V,E,R,T);
const Tag TAG_INDX = TAG(I,N,D,X);
// ======================================================================
IndexedTriangleList::IndexedTriangleList() :
m_mergeVertices(false),
m_epsilon(0.0f),
m_vertices(new std::vector<Vector>),
m_indices(new std::vector<int>)
{
}
// ----------------------------------------------------------------------
IndexedTriangleList::IndexedTriangleList(Iff & iff) :
m_mergeVertices(false),
m_epsilon(0.0f),
m_vertices(new std::vector<Vector>),
m_indices(new std::vector<int>)
{
load(iff);
}
// ----------------------------------------------------------------------
IndexedTriangleList::~IndexedTriangleList()
{
delete m_vertices;
delete m_indices;
}
// ----------------------------------------------------------------------
const std::vector<Vector> &IndexedTriangleList::getVertices() const
{
return *m_vertices;
}
// ----------
const std::vector<int> &IndexedTriangleList::getIndices() const
{
return *m_indices;
}
// ----------------------------------------------------------------------
std::vector<Vector> &IndexedTriangleList::getVertices()
{
return *m_vertices;
}
// ----------
std::vector<int> &IndexedTriangleList::getIndices()
{
return *m_indices;
}
// ----------------------------------------------------------------------
void IndexedTriangleList::load(Iff &iff)
{
clear();
iff.enterForm(TAG_IDTL);
switch (iff.getCurrentName())
{
case TAG_0000:
load_0000(iff);
break;
default:
{
char buffer[512];
iff.formatLocation(buffer, sizeof(buffer));
DEBUG_FATAL(true, ("Unknown version number %s", buffer));
}
}
iff.exitForm(TAG_IDTL);
}
// ----------------------------------------------------------------------
void IndexedTriangleList::load_0000(Iff &iff)
{
iff.enterForm(TAG_0000);
iff.enterChunk(TAG_VERT);
{
const uint numberOfVertices = static_cast<uint>( iff.getChunkLengthLeft(3 * sizeof(float)) );
DEBUG_FATAL(!numberOfVertices, ("No vertices"));
m_vertices->resize(numberOfVertices);
iff.read_floatVector( static_cast<int>(numberOfVertices), &(*m_vertices)[0]);
}
iff.exitChunk(TAG_VERT);
iff.enterChunk(TAG_INDX);
{
const uint numberOfIndices = static_cast<uint>( iff.getChunkLengthLeft(sizeof(int32)) );
DEBUG_FATAL(!numberOfIndices, ("No indices"));
m_indices->resize(numberOfIndices);
for (uint i = 0; i < numberOfIndices; ++i)
(*m_indices)[i] = iff.read_int32();
}
iff.exitChunk(TAG_INDX);
iff.exitForm(TAG_0000);
}
// ----------------------------------------------------------------------
void IndexedTriangleList::write(Iff &iff) const
{
iff.insertForm(TAG_IDTL);
iff.insertForm(TAG_0000);
iff.insertChunk(TAG_VERT);
{
const uint numberOfVertices = m_vertices->size();
for (uint i = 0; i < numberOfVertices; ++i)
iff.insertChunkFloatVector((*m_vertices)[i]);
}
iff.exitChunk(TAG_VERT);
iff.insertChunk(TAG_INDX);
{
const uint numberOfIndices = m_indices->size();
for (uint i = 0; i < numberOfIndices; ++i)
iff.insertChunkData(static_cast<int32>((*m_indices)[i]));
}
iff.exitChunk(TAG_INDX);
iff.exitForm(TAG_0000);
iff.exitForm(TAG_IDTL);
}
// ----------------------------------------------------------------------
void IndexedTriangleList::clear()
{
m_vertices->clear();
m_indices->clear();
}
// ----------------------------------------------------------------------
void IndexedTriangleList::addVertices(const Vector *vertices, int numberOfVertices, std::vector<int> &indices)
{
indices.reserve( static_cast<uint>(numberOfVertices) );
if (m_mergeVertices)
{
for (int i = 0; i < numberOfVertices; ++i)
{
// look for a matching vertex
uint j = 0;
for ( ; j < m_vertices->size() && vertices[i] != (*m_vertices)[j] && vertices[i].magnitudeBetween((*m_vertices)[j]) > m_epsilon; ++j)
{}
if (j >= m_vertices->size())
{
indices.push_back(static_cast<int>(m_vertices->size()));
m_vertices->push_back(vertices[i]);
}
else
indices.push_back( static_cast<int>(j) );
}
}
else
{
for (int i = 0; i < numberOfVertices; ++i)
{
indices.push_back(static_cast<int>(m_vertices->size()));
m_vertices->push_back(vertices[i]);
}
}
}
// ----------------------------------------------------------------------
void IndexedTriangleList::addTriangleList(const Vector *vertices, int numberOfVertices)
{
DEBUG_FATAL(numberOfVertices < 3 || numberOfVertices % 3 != 0, ("Invalid number of vertices for a triangle list %d", numberOfVertices));
std::vector<int> vertexIndices;
addVertices(vertices, numberOfVertices, vertexIndices);
for (uint i = 0; i < static_cast<uint>(numberOfVertices); ++i)
m_indices->push_back(vertexIndices[i]);
}
// ----------------------------------------------------------------------
void IndexedTriangleList::addTriangleStrip(const Vector *vertices, int numberOfVertices)
{
DEBUG_FATAL(numberOfVertices < 3, ("Invalid number of vertices for a triangle strip %d", numberOfVertices));
std::vector<int> vertexIndices;
addVertices(vertices, numberOfVertices, vertexIndices);
const uint triangleCount = static_cast<uint>(numberOfVertices) - 2;
for (uint i = 0; i < triangleCount; ++i)
if (i & 1)
{
m_indices->push_back(vertexIndices[i+0]);
m_indices->push_back(vertexIndices[i+2]);
m_indices->push_back(vertexIndices[i+1]);
}
else
{
m_indices->push_back(vertexIndices[i+0]);
m_indices->push_back(vertexIndices[i+1]);
m_indices->push_back(vertexIndices[i+2]);
}
}
// ----------------------------------------------------------------------
void IndexedTriangleList::addTriangleFan(const Vector *vertices, int numberOfVertices)
{
DEBUG_FATAL(numberOfVertices < 3, ("Invalid number of vertices for a triangle fan %d", numberOfVertices));
std::vector<int> vertexIndices;
addVertices(vertices, numberOfVertices, vertexIndices);
const uint triangleCount = static_cast<uint>(numberOfVertices) - 2;
for (uint i = 0; i < triangleCount; ++i)
{
m_indices->push_back(vertexIndices[0]);
m_indices->push_back(vertexIndices[i+1]);
m_indices->push_back(vertexIndices[i+2]);
}
}
// ----------------------------------------------------------------------
void IndexedTriangleList::addIndexedTriangleList(const Vector *vertices, int numberOfVertices, const int *indices, int numberOfIndices)
{
DEBUG_FATAL(numberOfVertices < 3, ("Invalid number of vertices for an indexed triangle list %d", numberOfVertices));
DEBUG_FATAL(numberOfIndices < 3 || numberOfIndices % 3 != 0, ("Invalid number of indices for an indexed triangle list %d", numberOfIndices));
std::vector<int> vertexIndices;
addVertices(vertices, numberOfVertices, vertexIndices);
for (uint i = 0; i < static_cast<uint>(numberOfIndices); ++i)
{
uint index = static_cast<uint>(indices[i]);
m_indices->push_back(vertexIndices[index]);
}
}
// ----------------------------------------------------------------------
void IndexedTriangleList::addIndexedTriangleStrip(const Vector *vertices, int numberOfVertices, const int *indices, int numberOfIndices)
{
DEBUG_FATAL(numberOfVertices < 3, ("Invalid number of vertices for an indexed triangle list %d", numberOfVertices));
DEBUG_FATAL(numberOfIndices < 3, ("Invalid number of indices for an indexed triangle strip %d", numberOfIndices));
std::vector<int> vertexIndices;
addVertices(vertices, numberOfVertices, vertexIndices);
const uint triangleCount = static_cast<uint>(numberOfIndices) - 2;
for (uint i = 0; i < triangleCount; ++i)
{
if (i & 1)
{
m_indices->push_back(vertexIndices[ static_cast<uint>(indices[i+0]) ]);
m_indices->push_back(vertexIndices[ static_cast<uint>(indices[i+2]) ]);
m_indices->push_back(vertexIndices[ static_cast<uint>(indices[i+1]) ]);
}
else
{
m_indices->push_back(vertexIndices[ static_cast<uint>(indices[i+0]) ]);
m_indices->push_back(vertexIndices[ static_cast<uint>(indices[i+1]) ]);
m_indices->push_back(vertexIndices[ static_cast<uint>(indices[i+2]) ]);
}
}
}
// ----------------------------------------------------------------------
void IndexedTriangleList::addIndexedTriangleFan(const Vector *vertices, int numberOfVertices, const int *indices, int numberOfIndices)
{
DEBUG_FATAL(numberOfVertices < 3, ("Invalid number of vertices for an indexed triangle list %d", numberOfVertices));
DEBUG_FATAL(numberOfIndices < 3, ("Invalid number of indices for an indexed triangle fan %d", numberOfIndices));
std::vector<int> vertexIndices;
addVertices(vertices, numberOfVertices, vertexIndices);
const uint triangleCount = static_cast<uint>(numberOfIndices) - 2;
for (uint i = 0; i < triangleCount; ++i)
{
m_indices->push_back(vertexIndices[ static_cast<uint>(indices[0])]);
m_indices->push_back(vertexIndices[ static_cast<uint>(indices[i+1])]);
m_indices->push_back(vertexIndices[ static_cast<uint>(indices[i+2])]);
}
}
// ----------------------------------------------------------------------
IndexedTriangleList * IndexedTriangleList::clone() const
{
IndexedTriangleList * const indexedTriangleList = new IndexedTriangleList();
indexedTriangleList->copy(this);
return indexedTriangleList;
}
// ----------------------------------------------------------------------
void IndexedTriangleList::copy(IndexedTriangleList const * const indexedTriangleList)
{
m_mergeVertices = indexedTriangleList->m_mergeVertices;
m_epsilon = indexedTriangleList->m_epsilon;
*m_vertices = *indexedTriangleList->m_vertices;
*m_indices = *indexedTriangleList->m_indices;
}
// ----------------------------------------------------------------------
bool IndexedTriangleList::collide(Vector const & start, Vector const & end, Vector & result) const
{
return collide(start, end, *m_indices, result);
}
// ----------------------------------------------------------------------
bool IndexedTriangleList::collide(Vector const & start, Vector const & end, std::vector<int> const & indices, Vector & result) const
{
bool found = false;
Vector shortenedEnd(end);
Vector const direction(end - start);
Vector normal;
Plane plane;
Vector intersection;
std::vector<Vector> const & vertices = *m_vertices;
uint const numberOfIndices = indices.size();
for (int index = 0; static_cast<int>(numberOfIndices - index) >= 3; /*increment in body*/)
{
Vector const & v0 = vertices[indices[index++]];
Vector const & v1 = vertices[indices[index++]];
Vector const & v2 = vertices[indices[index++]];
//-- Compute normal
normal = (v0 - v2).cross(v1 - v0);
//-- Ignore backfaces. (Use float min to prevent precision errors.)
if (direction.dot(normal) < std::numeric_limits<float>::min())
{
//-- It doesn't matter that the normal is not normalized
plane.set(normal, v0);
//-- See if the end points intersect the plane the polygon lies on, lies within the polygon, and is closer to start than the previous point
if ((plane.findDirectedIntersection(start, shortenedEnd, intersection)) &&
(start.magnitudeBetweenSquared(intersection) < start.magnitudeBetweenSquared(shortenedEnd)) &&
(intersection.inPolygon(v0, v1, v2)))
{
found = true;
result = intersection;
shortenedEnd = intersection;
}
}
}
return found;
}
// ======================================================================
@@ -0,0 +1,89 @@
// ======================================================================
//
// IndexedTriangleList.h
// Copyright 2001 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_IndexedTriangleList_H
#define INCLUDED_IndexedTriangleList_H
// ======================================================================
class Iff;
class Vector;
// ======================================================================
class IndexedTriangleList
{
public:
IndexedTriangleList();
explicit IndexedTriangleList(Iff &iff);
~IndexedTriangleList();
const stdvector<Vector>::fwd &getVertices() const;
const stdvector<int>::fwd &getIndices() const;
stdvector<Vector>::fwd &getVertices();
stdvector<int>::fwd &getIndices();
void load(Iff &iff);
void write(Iff &iff) const;
void allowVertexMerging(bool mergeVertices);
void setVertexMergeEpsilon(float epsilon);
void clear();
void addTriangleList(const Vector *vertices, int numberOfVertices);
void addTriangleStrip(const Vector *vertices, int numberOfVertices);
void addTriangleFan(const Vector *vertices, int numberOfVertices);
void addIndexedTriangleList(const Vector *vertices, int numberOfVertices, const int *indices, int numberOfIndices);
void addIndexedTriangleStrip(const Vector *vertices, int numberOfVertices, const int *indices, int numberOfIndices);
void addIndexedTriangleFan(const Vector *vertices, int numberOfVertices, const int *indices, int numberOfIndices);
IndexedTriangleList* clone() const;
void copy(const IndexedTriangleList *tris);
bool collide(Vector const & start, Vector const & end, Vector & result) const;
bool collide(Vector const & start, Vector const & end, stdvector<int>::fwd const & indices, Vector & result) const;
private:
// disabled
IndexedTriangleList(const IndexedTriangleList &);
IndexedTriangleList &operator =(const IndexedTriangleList &);
private:
void load_0000(Iff &iff);
void addVertices(const Vector *vertices, int numberOfVertices, stdvector<int>::fwd &indices);
private:
bool m_mergeVertices;
float m_epsilon;
stdvector<Vector>::fwd * const m_vertices;
stdvector<int>::fwd * const m_indices;
};
// ======================================================================
inline void IndexedTriangleList::allowVertexMerging(bool mergeVertices)
{
m_mergeVertices = mergeVertices;
}
// ----------------------------------------------------------------------
inline void IndexedTriangleList::setVertexMergeEpsilon(float epsilon)
{
m_epsilon = epsilon;
}
// ======================================================================
#endif
@@ -0,0 +1,156 @@
//===================================================================
//
// Line2d.h
// asommers
//
// copyright 2001, sony online entertainment
//
//===================================================================
#ifndef INCLUDED_Line2d_H
#define INCLUDED_Line2d_H
//===================================================================
#include "Vector2d.h"
//===================================================================
class Line2d
{
private:
Vector2d m_normal;
float m_c;
public:
Line2d ();
Line2d (float x0, float y0, float x1, float y1);
Line2d (const Vector2d& normal, float c);
Line2d (const Vector2d& point0, const Vector2d& point1);
void set (const Vector2d& normal, float c);
void set (const Vector2d& point0, const Vector2d& point1);
const Vector2d& getNormal () const;
const float getC () const;
float computeDistanceTo (const Vector2d& point) const;
const Vector2d project (const Vector2d& point) const;
bool findIntersection(Vector2d const & point0, Vector2d const & point1, Vector2d & intersection) const;
};
//===================================================================
inline Line2d::Line2d () :
m_normal (1.f, 0.f),
m_c (0.f)
{
}
//-------------------------------------------------------------------
inline Line2d::Line2d (float const x0, float const y0, float const x1, float const y1) :
m_normal(),
m_c(0.f)
{
set(Vector2d(x0, y0), Vector2d(x1, y1));
}
//-------------------------------------------------------------------
inline Line2d::Line2d (const Vector2d& normal, float c) :
m_normal (normal),
m_c (c)
{
}
//-------------------------------------------------------------------
inline Line2d::Line2d (const Vector2d& point0, const Vector2d& point1) :
m_normal (),
m_c (0.f)
{
set (point0, point1);
}
//-------------------------------------------------------------------
inline void Line2d::set (const Vector2d& normal, float c)
{
m_normal = normal;
m_c = c;
}
//-------------------------------------------------------------------
inline void Line2d::set (const Vector2d& point0, const Vector2d& point1)
{
m_normal.set (-point1.y + point0.y, point1.x - point0.x);
if (!m_normal.normalize ())
{
m_normal.set (1.f, 0.f);
DEBUG_FATAL (true, ("Line::set could not normalize vector"));
}
m_c = -m_normal.dot (point0);
}
//-------------------------------------------------------------------
inline const Vector2d& Line2d::getNormal () const
{
return m_normal;
}
//-------------------------------------------------------------------
inline const float Line2d::getC () const
{
return m_c;
}
//-------------------------------------------------------------------
inline float Line2d::computeDistanceTo (const Vector2d& point) const
{
return m_normal.dot (point) + m_c;
}
//-------------------------------------------------------------------
inline const Vector2d Line2d::project (const Vector2d& point) const
{
return point - (m_normal * computeDistanceTo (point));
}
//-------------------------------------------------------------------
inline bool Line2d::findIntersection(Vector2d const & start, Vector2d const & end, Vector2d & intersection) const
{
float const t0(computeDistanceTo(start));
float const t1(computeDistanceTo(end));
// check to make sure the endpoints span the plane
if ((t0 * t1) > 0.f)
return false;
// both zero
if (t0 == t1)
{
intersection = start;
return true;
}
// safe since sign of t0 is always opposite t1
float const t = t0 / (t0 - t1);
intersection.x = start.x + (end.x - start.x) * t;
intersection.y = start.y + (end.y - start.y) * t;
return true;
}
//===================================================================
#endif
@@ -0,0 +1,520 @@
// ======================================================================
//
// MxCifQuadTree.cpp
//
// Copyright 2002, Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/MxCifQuadTree.h"
#include "sharedMath/MxCifQuadTreeBounds.h"
//==============================================================================
/**
* Class constructor.
*
* @param minX min x coordinate of our area
* @param minY min y coordinate of our area
* @param maxX max x coordinate of our area
* @param maxY max y coordinate of our area
* @param maxDepth max depth of this tree
*/
MxCifQuadTree::MxCifQuadTree(float minX, float minY, float maxX, float maxY, int maxDepth) :
m_minX(minX),
m_minY(minY),
m_maxX(maxX),
m_maxY(maxY),
m_centerX((m_maxX - m_minX) / 2.0f + m_minX),
m_centerY((m_maxY - m_minY) / 2.0f + m_minY),
m_maxDepth(maxDepth),
m_urTree(NULL),
m_ulTree(NULL),
m_llTree(NULL),
m_lrTree(NULL),
m_xAxisTree(minX, maxX, maxDepth),
m_yAxisTree(minY, maxY, maxDepth)
{
} // MxCifQuadTree::MxCifQuadTree
//------------------------------------------------------------------------------
/**
* Class destructor.
*/
MxCifQuadTree::~MxCifQuadTree()
{
delete m_urTree;
m_urTree = NULL;
delete m_ulTree;
m_ulTree = NULL;
delete m_llTree;
m_llTree = NULL;
delete m_lrTree;
m_lrTree = NULL;
} // MxCifQuadTree::~MxCifQuadTree
//------------------------------------------------------------------------------
/**
* Splits this quad into four sub-quads.
*
* @return true if we split, false if we have reaced the max depth
*/
bool MxCifQuadTree::split(void)
{
if (m_maxDepth <= 1)
return false;
int newDepth = m_maxDepth - 1;
m_urTree = new MxCifQuadTree(m_centerX, m_centerY, m_maxX, m_maxY, newDepth);
m_ulTree = new MxCifQuadTree( m_minX, m_centerY, m_centerX, m_maxY, newDepth);
m_llTree = new MxCifQuadTree( m_minX, m_minY, m_centerX, m_centerY, newDepth);
m_lrTree = new MxCifQuadTree(m_centerX, m_minY, m_maxX, m_centerY, newDepth);
return true;
} // MxCifQuadTree::split
//------------------------------------------------------------------------------
/**
* Adds an object to the tree.
*
* @param object the object to add
*
* @return true if the object was added, false if not
*/
bool MxCifQuadTree::addObject(const MxCifQuadTreeBounds & object)
{
// see if the object fits entirely within us
if (object.getMaxX() <= m_maxX &&
object.getMaxY() <= m_maxY &&
object.getMinX() >= m_minX &&
object.getMinY() >= m_minY)
{
// try putting the object in a child node
if (m_maxDepth > 1)
{
if (m_urTree == NULL)
{
if (!split())
return false;
}
if (m_urTree->addObject(object) ||
m_ulTree->addObject(object) ||
m_llTree->addObject(object) ||
m_lrTree->addObject(object))
{
return true;
}
// put the object into one of the axis trees
if (object.getMaxX() < m_centerX ||
object.getMinX() > m_centerX)
{
// add the object to our x-axis tree
m_xAxisTree.addObject(object);
}
else
{
// add the object to our y-axis tree
m_yAxisTree.addObject(object);
}
return true;
}
else
{
// can't subdivide further, add the object to our list
if (object.getMaxX() - object.getMinX() < object.getMaxY() - object.getMinY())
m_xAxisTree.addObject(object);
else
m_yAxisTree.addObject(object);
return true;
}
}
else
return false;
} // MxCifQuadTree::addObject
//------------------------------------------------------------------------------
/**
* Removes an object from the tree.
*
* @param object the object to remove
*
* @return true if the object was removed, false if not
*/
bool MxCifQuadTree::removeObject(const MxCifQuadTreeBounds & object)
{
// see if the object fits entirely within us
if (object.getMaxX() <= m_maxX &&
object.getMaxY() <= m_maxY &&
object.getMinX() >= m_minX &&
object.getMinY() >= m_minY)
{
if (m_maxDepth > 1)
{
if (m_urTree != NULL)
{
// check if the object is in a sub-node
if (m_urTree->removeObject(object) ||
m_ulTree->removeObject(object) ||
m_llTree->removeObject(object) ||
m_lrTree->removeObject(object))
{
return true;
}
}
// remove the object from one of the axis trees
if (object.getMaxX() < m_centerX ||
object.getMinX() > m_centerX)
{
return m_xAxisTree.removeObject(object);
}
else
{
return m_yAxisTree.removeObject(object);
}
}
else
{
// can't subdivide further, remove the object from an axis tree
if (object.getMaxX() - object.getMinX() < object.getMaxY() - object.getMinY())
return m_xAxisTree.removeObject(object);
else
return m_yAxisTree.removeObject(object);
}
}
else
return false;
} // MxCifQuadTree::removeObject
//------------------------------------------------------------------------------
/**
* Finds all the objects that contain a given point.
*
* @param x x coordinate of the point
* @param y y coordinate of the point
* @param objects vector that will be filled in with the objects that contain the point
*/
void MxCifQuadTree::getObjectsAt(float x, float y,
std::vector<const MxCifQuadTreeBounds *> & objects) const
{
// find if we contain the point
if (x <= m_maxX &&
x >= m_minX &&
y <= m_maxY &&
y >= m_minY)
{
// if we have sub-trees, pass the point to the tree that contains it
if (m_urTree != NULL)
{
if (x >= m_centerX && y >= m_centerY)
m_urTree->getObjectsAt(x, y, objects);
else if (x <= m_centerX && y >= m_centerY)
m_ulTree->getObjectsAt(x, y, objects);
else if (x <= m_centerX && y <= m_centerY)
m_llTree->getObjectsAt(x, y, objects);
else
m_lrTree->getObjectsAt(x, y, objects);
}
// test the objects in our axis trees
m_xAxisTree.getObjectsAt(x, y, objects);
m_yAxisTree.getObjectsAt(x, y, objects);
}
} // MxCifQuadTree::getObjectsAt
//------------------------------------------------------------------------------
/**
* Returns all the objects in the tree.
*
* @param objects vector that will be filled in with the objects
*/
void MxCifQuadTree::getAllObjects(std::vector<const MxCifQuadTreeBounds *> & objects) const
{
// if we have sub-trees, pass the point to the tree that contains it
if (m_urTree != NULL)
{
m_urTree->getAllObjects(objects);
m_ulTree->getAllObjects(objects);
m_llTree->getAllObjects(objects);
m_lrTree->getAllObjects(objects);
}
m_xAxisTree.getAllObjects(objects);
m_yAxisTree.getAllObjects(objects);
} // MxCifQuadTree::getAllObjects
//==============================================================================
/**
* Class constructor.
*
* @param min min range value
* @param min max range value
* @param maxDepth max depth of this tree
*/
MxCifQuadTree::MxCifBinTree::MxCifBinTree(float min, float max, int maxDepth) :
m_min(min),
m_max(max),
m_center((max - min) / 2.0f + min),
m_maxDepth(maxDepth),
m_left(NULL),
m_right(NULL),
m_objects()
{
} // MxCifBinTree::MxCifBinTree
/**
* Class destructor.
*/
MxCifQuadTree::MxCifBinTree::~MxCifBinTree()
{
delete m_left;
m_left = NULL;
delete m_right;
m_right = NULL;
m_objects.clear();
} // MxCifBinTree::~MxCifBinTree
/**
* Splits this tree into two sub-trees.
*
* @return true if we split, false if we have reaced the max depth
*/
bool MxCifQuadTree::MxCifBinTree::split(void)
{
if (m_maxDepth <= 1)
return false;
int newDepth = m_maxDepth - 1;
m_left = createChild( m_min, m_center, newDepth);
m_right = createChild(m_center, m_max, newDepth);
return true;
} // MxCifBinTree::split
/**
* Adds an object to the tree.
*
* @param object the object to add
*
* @return true if the object was added, false if not
*/
bool MxCifQuadTree::MxCifBinTree::addObject(const MxCifQuadTreeBounds & object)
{
// see if the object fits entirely within us
if (isObjectInRange(object))
{
// try putting the object in a child node
if (m_maxDepth > 1)
{
if (m_left == NULL)
{
if (!split())
return false;
}
if (m_left->addObject(object) ||
m_right->addObject(object))
{
return true;
}
}
// add the object to us
m_objects.push_back(&object);
return true;
}
else
return false;
} // MxCifBinTree::addObject
/**
* Removes an object from the tree.
*
* @param object the object to remove
*
* @return true if the object was removed, false if not
*/
bool MxCifQuadTree::MxCifBinTree::removeObject(const MxCifQuadTreeBounds & object)
{
// see if the object fits entirely within us
if (isObjectInRange(object))
{
if (m_maxDepth > 1)
{
if (m_left != NULL)
{
// check if the object is in a sub-node
if (m_left->removeObject(object) ||
m_right->removeObject(object))
{
return true;
}
}
}
// remove the object from us
std::vector<const MxCifQuadTreeBounds *>::iterator result = std::find(
m_objects.begin(), m_objects.end(), &object);
if (result != m_objects.end())
{
m_objects.erase(result);
return true;
}
}
return false;
} // MxCifBinTree::removeObject
/**
* Returns all the objects in the tree.
*
* @param objects vector that will be filled in with the objects that contain the point
*/
void MxCifQuadTree::MxCifBinTree::getAllObjects(
std::vector<const MxCifQuadTreeBounds *> & objects) const
{
// if we have sub-trees, pass the point to the tree that contains it
if (m_left != NULL)
{
m_right->getAllObjects(objects);
m_left->getAllObjects(objects);
}
for (std::vector<const MxCifQuadTreeBounds *>::const_iterator iter = m_objects.begin();
iter != m_objects.end(); ++iter)
{
objects.push_back(*iter);
}
} // MxCifBinTree::getAllObjects
//==============================================================================
/**
* Class destructor.
*/
MxCifQuadTree::MxCifXBinTree::~MxCifXBinTree()
{
} // MxCifXBinTree::~MxCifXBinTree
/**
* Checks if an object's x-axis range is contained within our range.
*
* @param object the object to check
*
* @return true if we caontain the object, false if not
*/
bool MxCifQuadTree::MxCifXBinTree::isObjectInRange(const MxCifQuadTreeBounds & object) const
{
// see if the object fits entirely within us
if (object.getMaxX() <= m_max &&
object.getMinX() >= m_min)
{
return true;
}
return false;
} // MxCifXBinTree::isObjectInRange
/**
* Finds all the objects that contain a given point.
*
* @param x x coordinate of the point
* @param y y coordinate of the point
* @param objects vector that will be filled in with the objects that contain the point
*/
void MxCifQuadTree::MxCifXBinTree::getObjectsAt(float x, float y,
std::vector<const MxCifQuadTreeBounds *> & objects) const
{
// find if we contain the point
if (x <= m_max &&
x >= m_min)
{
// if we have sub-trees, pass the point to the tree that contains it
if (m_left != NULL)
{
if (x >= m_center)
m_right->getObjectsAt(x, y, objects);
else
m_left->getObjectsAt(x, y, objects);
}
// check against each object in our list
for (std::vector<const MxCifQuadTreeBounds *>::const_iterator iter = m_objects.begin();
iter != m_objects.end(); ++iter)
{
const MxCifQuadTreeBounds * object = *iter;
if (object->isPointIn(x, y))
{
objects.push_back(object);
}
}
}
} // MxCifXBinTree::getObjectsAt
//==============================================================================
/**
* Class destructor.
*/
MxCifQuadTree::MxCifYBinTree::~MxCifYBinTree()
{
} // MxCifYBinTree::~MxCifYBinTree
/**
* Checks if an object's y-axis range is contained within our range.
*
* @param object the object to check
*
* @return true if we caontain the object, false if not
*/
bool MxCifQuadTree::MxCifYBinTree::isObjectInRange(const MxCifQuadTreeBounds & object) const
{
// see if the object fits entirely within us
if (object.getMaxY() <= m_max &&
object.getMinY() >= m_min)
{
return true;
}
return false;
} // MxCifYBinTree::isObjectInRange
/**
* Finds all the objects that contain a given point.
*
* @param x x coordinate of the point
* @param y y coordinate of the point
* @param objects vector that will be filled in with the objects that contain the point
*/
void MxCifQuadTree::MxCifYBinTree::getObjectsAt(float x, float y,
std::vector<const MxCifQuadTreeBounds *> & objects) const
{
// find if we contain the point
if (y <= m_max &&
y >= m_min)
{
// if we have sub-trees, pass the point to the tree that contains it
if (m_left != NULL)
{
if (y >= m_center)
m_right->getObjectsAt(x, y, objects);
else
m_left->getObjectsAt(x, y, objects);
}
// check against each object in our list
for (std::vector<const MxCifQuadTreeBounds *>::const_iterator iter = m_objects.begin();
iter != m_objects.end(); ++iter)
{
const MxCifQuadTreeBounds * object = *iter;
if (object->isPointIn(x, y))
{
objects.push_back(object);
}
}
}
} // MxCifYBinTree::getObjectsAt
//==============================================================================
@@ -0,0 +1,163 @@
// ======================================================================
//
// MxCifQuadTree.h
//
// Copyright 2002, Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_MxCifQuadTree_H
#define INCLUDED_MxCifQuadTree_H
#include <vector>
//==============================================================================
/*******************************************************************************
An mx-cif quadtree is a quadtree that stores an object at the minimum quad
that completely contains the object. They are further sub-divided into a
one-dimentional variation of the mx-cif quadtree (mx-cif bintree) based on
if the object crosses the x or y axis of the quad (objects that cross both are
placed in the y-axis bintree).
There is an optimization of the mx-cif quadtree that could be implemented (at
the expense of more memory) where the object is sub-divided and put into
a quad one lower than its normal level. This is very similar to what is done
in bsp trees.
See http://www.cs.umd.edu/users/brabec/quadtree/rectangles/cifquad.html, or
"Design and Analysis of Spatial Data Structures" by H. Samet (which
unfortunately is out of print).
*******************************************************************************/
//==============================================================================
class MxCifQuadTreeBounds;
//==============================================================================
class MxCifQuadTree
{
public:
MxCifQuadTree(float minX, float minY, float maxX, float maxY, int maxDepth);
~MxCifQuadTree();
bool addObject(const MxCifQuadTreeBounds & object);
bool removeObject(const MxCifQuadTreeBounds & object);
void getObjectsAt(float x, float y, std::vector<const MxCifQuadTreeBounds *> & objects) const;
void getAllObjects(std::vector<const MxCifQuadTreeBounds *> & objects) const;
private:
/**
* A one-dimentional variation of an MxCifQuadTree
*/
class MxCifBinTree
{
public:
MxCifBinTree(float min, float max, int maxDepth);
virtual ~MxCifBinTree();
bool addObject(const MxCifQuadTreeBounds & object);
bool removeObject(const MxCifQuadTreeBounds & object);
virtual void getObjectsAt(float x, float y, std::vector<const MxCifQuadTreeBounds *> & objects) const = 0;
void getAllObjects(std::vector<const MxCifQuadTreeBounds *> & objects) const;
protected:
bool split(void);
virtual MxCifBinTree * createChild(float min, float max, int maxDepth) const = 0;
virtual bool isObjectInRange(const MxCifQuadTreeBounds & object) const = 0;
protected:
float m_min; // min value of our range
float m_max; // max value of our range
float m_center; // center range value computed from the bounds
int m_maxDepth; // max depth we can recurse from our level
MxCifBinTree * m_left; // left child
MxCifBinTree * m_right; // right child
// @todo: use an auto_ptr here?
std::vector<const MxCifQuadTreeBounds *> m_objects; // objects that are contained in our bounds
};
/**
* An MxCifBinTree optimized for searches in the X direction.
*/
class MxCifXBinTree : public MxCifBinTree
{
public:
MxCifXBinTree(float min, float max, int maxDepth);
virtual ~MxCifXBinTree();
virtual void getObjectsAt(float x, float y, std::vector<const MxCifQuadTreeBounds *> & objects) const;
protected:
virtual MxCifBinTree * createChild(float min, float max, int maxDepth) const
{
return new MxCifXBinTree(min, max, maxDepth);
}
virtual bool isObjectInRange(const MxCifQuadTreeBounds & object) const;
};
/**
* An MxCifBinTree optimized for searches in the Y direction.
*/
class MxCifYBinTree : public MxCifBinTree
{
public:
MxCifYBinTree(float min, float max, int maxDepth);
virtual ~MxCifYBinTree();
virtual void getObjectsAt(float x, float y, std::vector<const MxCifQuadTreeBounds *> & objects) const;
protected:
virtual MxCifBinTree * createChild(float min, float max, int maxDepth) const
{
return new MxCifXBinTree(min, max, maxDepth);
}
virtual bool isObjectInRange(const MxCifQuadTreeBounds & object) const;
};
private:
bool split(void);
private:
float m_minX, m_minY; // lower-left bound
float m_maxX, m_maxY; // upper-right bound
float m_centerX, m_centerY; // center computed from the bounds
int m_maxDepth; // max depth we can recurse from our level
MxCifQuadTree * m_urTree; // upper-right child
MxCifQuadTree * m_ulTree; // upper-left child
MxCifQuadTree * m_llTree; // lower-left child
MxCifQuadTree * m_lrTree; // lower-right child
MxCifXBinTree m_xAxisTree; // objects that have a minimum intersection of the x-axis
MxCifYBinTree m_yAxisTree; // objects that have a minimum intersection of the -axis
};
//==============================================================================
inline MxCifQuadTree::MxCifXBinTree::MxCifXBinTree(float min, float max, int maxDepth) :
MxCifQuadTree::MxCifBinTree(min, max, maxDepth)
{
}
inline MxCifQuadTree::MxCifYBinTree::MxCifYBinTree(float min, float max, int maxDepth) :
MxCifQuadTree::MxCifBinTree(min, max, maxDepth)
{
}
#endif // INCLUDED_MxCifQuadTree_H
@@ -0,0 +1,41 @@
// ======================================================================
//
// MxCifQuadTreeBounds.cpp
//
// Copyright 2002, Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/MxCifQuadTreeBounds.h"
/**
* Returns if a given point is in our area.
*
* @param x x coordinate of the point
* @param y y coordinate of the point
*
* @return true we contain the point, false if not
*/
bool MxCifQuadTreeBounds::isPointIn(float x, float y) const
{
return (x >= m_minX && x <= m_maxX && y >= m_minY && y <= m_maxY);
} // MxCifQuadTreeBounds::isPointIn
//==============================================================================
/*
Returns if a given point is in our area.
*
* @param x x coordinate of the point
* @param y y coordinate of the point
*
* @return true we contain the point, false if not
*/
bool MxCifQuadTreeCircleBounds::isPointIn(float x, float y) const
{
float dx = x - m_centerX;
float dy = y - m_centerY;
return (dx * dx + dy * dy) <= m_radiusSquared;
} // MxCifQuadTreeCircleBounds::isPointIn
@@ -0,0 +1,141 @@
// ======================================================================
//
// MxCifQuadTreeBounds.h
//
// Copyright 2002, Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_MxCifQuadTreeBounds_H
#define INCLUDED_MxCifQuadTreeBounds_H
//==============================================================================
/**
* Base class used in MxCifQuadTree. Keeps track of the bounds of a 2-d geometric
* shape.
*/
class MxCifQuadTreeBounds
{
public:
MxCifQuadTreeBounds(float minX, float minY, float maxX, float maxY, void * data = NULL);
const float getMinX(void) const;
const float getMinY(void) const;
const float getMaxX(void) const;
const float getMaxY(void) const;
void * getData(void) const;
virtual bool isPointIn(float x, float y) const;
private:
MxCifQuadTreeBounds();
MxCifQuadTreeBounds(const MxCifQuadTreeBounds &);
MxCifQuadTreeBounds & operator =(const MxCifQuadTreeBounds &);
private:
const float m_minX, m_minY; // lower-left bound (--)
const float m_maxX, m_maxY; // upper-right bound (++)
void * m_data; // data associated with the area
};
//------------------------------------------------------------------------------
inline MxCifQuadTreeBounds::MxCifQuadTreeBounds(float minX, float minY, float maxX,
float maxY, void * data) :
m_minX(minX),
m_minY(minY),
m_maxX(maxX),
m_maxY(maxY),
m_data(data)
{
}
inline const float MxCifQuadTreeBounds::getMinX(void) const
{
return m_minX;
}
inline const float MxCifQuadTreeBounds::getMinY(void) const
{
return m_minY;
}
inline const float MxCifQuadTreeBounds::getMaxX(void) const
{
return m_maxX;
}
inline const float MxCifQuadTreeBounds::getMaxY(void) const
{
return m_maxY;
}
inline void * MxCifQuadTreeBounds::getData(void) const
{
return m_data;
}
//==============================================================================
/**
* A circular area for use in a MxCifQuadTree.
*/
class MxCifQuadTreeCircleBounds : public MxCifQuadTreeBounds
{
public:
MxCifQuadTreeCircleBounds(float centerX, float centerY, float radius, void * data = NULL);
float getCenterX() const;
float getCenterY() const;
float getRadius() const;
virtual bool isPointIn(float x, float y) const;
private:
MxCifQuadTreeCircleBounds();
MxCifQuadTreeCircleBounds(const MxCifQuadTreeCircleBounds &);
MxCifQuadTreeCircleBounds & operator =(const MxCifQuadTreeCircleBounds &);
private:
const float m_centerX, m_centerY;
const float m_radius;
const float m_radiusSquared;
};
//------------------------------------------------------------------------------
inline MxCifQuadTreeCircleBounds::MxCifQuadTreeCircleBounds(float centerX,
float centerY, float radius, void * data) :
MxCifQuadTreeBounds(centerX - radius, centerY - radius, centerX + radius,
centerY + radius, data),
m_centerX(centerX),
m_centerY(centerY),
m_radius(radius),
m_radiusSquared(radius * radius)
{
}
inline float MxCifQuadTreeCircleBounds::getCenterX() const
{
return m_centerX;
}
inline float MxCifQuadTreeCircleBounds::getCenterY() const
{
return m_centerY;
}
inline float MxCifQuadTreeCircleBounds::getRadius() const
{
return m_radius;
}
//==============================================================================
#endif // INCLUDED_MxCifQuadTreeBounds_H
@@ -0,0 +1,64 @@
// ======================================================================
//
// PackedArgb.cpp
// copyright 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/PackedArgb.h"
#include "sharedMath/VectorArgb.h"
// ======================================================================
const real PackedArgb::oo255 = RECIP (255);
const PackedArgb PackedArgb::solidBlack (255, 0, 0, 0);
const PackedArgb PackedArgb::solidBlue (255, 0, 0, 255);
const PackedArgb PackedArgb::solidCyan (255, 0, 255, 255);
const PackedArgb PackedArgb::solidGreen (255, 0, 255, 0);
const PackedArgb PackedArgb::solidRed (255, 255, 0, 0);
const PackedArgb PackedArgb::solidMagenta (255, 255, 0, 255);
const PackedArgb PackedArgb::solidYellow (255, 255, 255, 0);
const PackedArgb PackedArgb::solidWhite (255, 255, 255, 255);
const PackedArgb PackedArgb::solidGray (255, 128, 128, 128);
// ======================================================================
PackedArgb const PackedArgb::linearInterpolate(PackedArgb const & color1, PackedArgb const & color2, float const t)
{
return PackedArgb(
static_cast<uint8>(::linearInterpolate(static_cast<int>(color1.getA()), static_cast<int>(color2.getA()), t)),
static_cast<uint8>(::linearInterpolate(static_cast<int>(color1.getR()), static_cast<int>(color2.getR()), t)),
static_cast<uint8>(::linearInterpolate(static_cast<int>(color1.getG()), static_cast<int>(color2.getG()), t)),
static_cast<uint8>(::linearInterpolate(static_cast<int>(color1.getB()), static_cast<int>(color2.getB()), t)));
}
// ======================================================================
/**
* Construct a PackedArgb value.
* @param argb The initial component values.
*/
//#include "sharedMath/VectorArgb.h"
PackedArgb::PackedArgb(const VectorArgb &argb)
: m_argb(convert(argb.a, argb.r, argb.g, argb.b))
{
}
// ----------------------------------------------------------------------
/**
* Set the color.
* @argb The new alpha and color value.
*/
void PackedArgb::setArgb(const VectorArgb &argb)
{
m_argb = convert(argb.a, argb.r, argb.g, argb.b);
}
// ======================================================================
@@ -0,0 +1,278 @@
// ======================================================================
//
// PackedArgb.h
// copyright 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_PackedArgb_H
#define INCLUDED_PackedArgb_H
// ======================================================================
class VectorArgb;
// ======================================================================
class PackedArgb
{
private:
static const real oo255;
public:
static const PackedArgb solidBlack;
static const PackedArgb solidBlue;
static const PackedArgb solidCyan;
static const PackedArgb solidGray;
static const PackedArgb solidGreen;
static const PackedArgb solidRed;
static const PackedArgb solidMagenta;
static const PackedArgb solidYellow;
static const PackedArgb solidWhite;
public:
static PackedArgb const linearInterpolate(PackedArgb const & color1, PackedArgb const & color2, float t);
public:
PackedArgb();
PackedArgb(uint32 argb);
PackedArgb(uint8 a, uint8 r, uint8 g, uint8 b);
PackedArgb(const VectorArgb &color);
uint32 getArgb() const;
uint8 getA() const;
uint8 getR() const;
uint8 getG() const;
uint8 getB() const;
void setArgb(uint32 Argb);
void setArgb(uint8 a, uint8 r, uint8 g, uint8 b);
void setArgb(const VectorArgb &argb);
void setA(uint8 a);
void setR(uint8 r);
void setG(uint8 g);
void setB(uint8 b);
bool operator==(const PackedArgb &rhs) const;
bool operator!=(const PackedArgb &rhs) const;
private:
static uint32 convert(uint8 a, uint8 r, uint8 g, uint8 b);
static uint32 convert(float a, float r, float g, float b);
private:
// The representation of this cannot change without ramification. At least
// VertexBuffer assumes it can cast a uint32 argb to a PackedArgb without error.
uint32 m_argb;
};
// ======================================================================
inline uint32 PackedArgb::convert(uint8 a, uint8 r, uint8 g, uint8 b)
{
return
static_cast<uint32>(a) << 24 |
static_cast<uint32>(r) << 16 |
static_cast<uint32>(g) << 8 |
static_cast<uint32>(b) << 0;
}
// ----------------------------------------------------------------------
inline uint32 PackedArgb::convert(float a, float r, float g, float b)
{
return convert(static_cast<uint8>(a * 255.0f), static_cast<uint8>(r * 255.0f), static_cast<uint8>(g * 255.0f), static_cast<uint8>(b * 255.0f));
}
// ======================================================================
/**
* Construct a default PackedArgb value.
* All components will be set to 0.
*/
inline PackedArgb::PackedArgb()
: m_argb(0)
{
}
// ----------------------------------------------------------------------
/**
* Construct a PackedArgb value.
* @param argb The initial component values.
*/
inline PackedArgb::PackedArgb(uint32 argb)
: m_argb(argb)
{
}
// ----------------------------------------------------------------------
/**
* Construct a PackedArgb value.
* @param a The initial alpha component.
* @param r The initial red component.
* @param g The initial green component.
* @param a The initial blue component.
*/
inline PackedArgb::PackedArgb (uint8 a, uint8 r, uint8 g, uint8 b)
: m_argb(convert(a, r, g, b))
{
}
// ----------------------------------------------------------------------
/**
* Return (a,r,g,b) value as a uint32 value with alpha component at MSB and blue component at LSB.
* @return the packed argb value
*/
inline uint32 PackedArgb::getArgb() const
{
return m_argb;
}
// ----------------------------------------------------------------------
/**
* Return the alpha component.
* @return the alpha component.
*/
inline uint8 PackedArgb::getA() const
{
return static_cast<uint8>((m_argb >> 24) & 0xff);
}
// ----------------------------------------------------------------------
/**
* Return the red component.
* @return the red component.
*/
inline uint8 PackedArgb::getR() const
{
return static_cast<uint8>((m_argb >> 16) & 0xff);
}
// ----------------------------------------------------------------------
/**
* Return the green component.
* @return the green component.
*/
inline uint8 PackedArgb::getG() const
{
return static_cast<uint8>((m_argb >> 8) & 0xff);
}
// ----------------------------------------------------------------------
/**
* Return the blue component.
* @return the blue component.
*/
inline uint8 PackedArgb::getB() const
{
return static_cast<uint8>((m_argb >> 0) & 0xff);
}
// ----------------------------------------------------------------------
/**
* Set the color.
* @param a Alpha value.
* @param r Red value.
* @param g Green value.
* @param b Blue value.
*/
inline void PackedArgb::setArgb(uint8 a, uint8 r, uint8 g, uint8 b)
{
m_argb = convert(a, r, g, b);
}
// ----------------------------------------------------------------------
/**
* Set the alpha and color.
* @param a Alpha value.
* @param r Red value.
* @param g Green value.
* @param b Blue value.
*/
inline void PackedArgb::setArgb(uint32 argb)
{
m_argb = argb;
}
// ----------------------------------------------------------------------
/**
* Set the alpha component.
* @param a New alpha component value.
*/
inline void PackedArgb::setA(uint8 a)
{
m_argb = (static_cast<uint32>(a) << 24) | (m_argb & 0x00ffffff);
}
// ----------------------------------------------------------------------
/**
* Set the red component.
* @param r New red component value.
*/
inline void PackedArgb::setR(uint8 r)
{
m_argb = (static_cast<uint32>(r) << 16) | (m_argb & 0xff00ffff);
}
// ----------------------------------------------------------------------
/**
* Set the red component.
* @param g New green component value.
*/
inline void PackedArgb::setG(uint8 g)
{
m_argb = (static_cast<uint32>(g) << 8) | (m_argb & 0xffff00ff);
}
// ----------------------------------------------------------------------
/**
* Set the red component.
* @param b New blue component value.
*/
inline void PackedArgb::setB(uint8 b)
{
m_argb = (static_cast<uint32>(b) << 0) | (m_argb & 0xffffff00);
}
// ----------------------------------------------------------------------
/**
* Compare two PackedArgb colors.
* @return true if all the components are identical, otherwise false.
*/
inline bool PackedArgb::operator==(const PackedArgb &rhs) const
{
return m_argb == rhs.m_argb;
}
// ----------------------------------------------------------------------
/**
* Compare two PackedArgb colors.
* @return true if any component is different, otherwise false.
*/
inline bool PackedArgb::operator !=(const PackedArgb& rhs) const
{
return !(*this == rhs);
}
// ======================================================================
#endif
@@ -0,0 +1,75 @@
//===================================================================
//
// PackedRgb.cpp
// asommers 6-20-2000
//
// copyright 2000, verant interactive
//
//===================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/PackedRgb.h"
#include "sharedMath/VectorArgb.h"
//===================================================================
const float PackedRgb::oo255 = RECIP (255);
const PackedRgb PackedRgb::solidBlack ( 0, 0, 0);
const PackedRgb PackedRgb::solidBlue ( 0, 0, 255);
const PackedRgb PackedRgb::solidCyan ( 0, 255, 255);
const PackedRgb PackedRgb::solidGreen ( 0, 255, 0);
const PackedRgb PackedRgb::solidRed (255, 0, 0);
const PackedRgb PackedRgb::solidMagenta (255, 0, 255);
const PackedRgb PackedRgb::solidYellow (255, 255, 0);
const PackedRgb PackedRgb::solidWhite (255, 255, 255);
const PackedRgb PackedRgb::solidGray (128, 128, 128);
const PackedRgb PackedRgb::solidOrange (255, 128, 0);
//===================================================================
VectorArgb PackedRgb::convert (float alpha) const
{
return VectorArgb (
alpha,
static_cast<float> (r) * oo255,
static_cast<float> (g) * oo255,
static_cast<float> (b) * oo255);
}
//-------------------------------------------------------------------
void PackedRgb::convert (const VectorArgb& color)
{
r = static_cast<uint8> (color.r * 255.f);
g = static_cast<uint8> (color.g * 255.f);
b = static_cast<uint8> (color.b * 255.f);
}
//-------------------------------------------------------------------
bool PackedRgb::operator== (const PackedRgb& rhs) const
{
return r == rhs.r && g == rhs.g && b == rhs.b;
}
//-------------------------------------------------------------------
bool PackedRgb::operator!= (const PackedRgb& rhs) const
{
return r != rhs.r || g != rhs.g || b != rhs.b;
}
//-------------------------------------------------------------------
const PackedRgb PackedRgb::linearInterpolate (const PackedRgb& color1, const PackedRgb& color2, float t)
{
return PackedRgb (
static_cast<uint8> (::linearInterpolate (static_cast<int> (color1.r), static_cast<int> (color2.r), t)),
static_cast<uint8> (::linearInterpolate (static_cast<int> (color1.g), static_cast<int> (color2.g), t)),
static_cast<uint8> (::linearInterpolate (static_cast<int> (color1.b), static_cast<int> (color2.b), t)));
}
//===================================================================
@@ -0,0 +1,87 @@
//===================================================================
//
// PackedRgb.h
// asommers 6-20-2000
//
// copyright 2000, verant interactive
//
//===================================================================
#ifndef INCLUDED_PackedRgb_H
#define INCLUDED_PackedRgb_H
//===================================================================
class VectorArgb;
//===================================================================
class PackedRgb
{
private:
static const float oo255;
public:
static const PackedRgb solidBlack;
static const PackedRgb solidBlue;
static const PackedRgb solidCyan;
static const PackedRgb solidGray;
static const PackedRgb solidGreen;
static const PackedRgb solidRed;
static const PackedRgb solidMagenta;
static const PackedRgb solidYellow;
static const PackedRgb solidWhite;
static const PackedRgb solidOrange;
public:
uint8 r;
uint8 g;
uint8 b;
public:
PackedRgb ();
PackedRgb (uint8 newR, uint8 newG, uint8 newB);
VectorArgb convert (float alpha=1.f) const;
void convert (const VectorArgb& color);
uint32 asUint32() const;
bool operator== (const PackedRgb& rhs) const;
bool operator!= (const PackedRgb& rhs) const;
static const PackedRgb linearInterpolate (const PackedRgb& color1, const PackedRgb& color2, float t);
};
//===================================================================
inline PackedRgb::PackedRgb () :
r (0),
g (0),
b (0)
{
}
//-------------------------------------------------------------------
inline PackedRgb::PackedRgb (uint8 newR, uint8 newG, uint8 newB) :
r (newR),
g (newG),
b (newB)
{
}
//-------------------------------------------------------------------
inline uint32 PackedRgb::asUint32() const
{
return (static_cast<uint32>(r) << 16) | (static_cast<uint32>(g) << 8) | (static_cast<uint32>(b) << 0);
}
//===================================================================
#endif
@@ -0,0 +1,609 @@
// ======================================================================
//
// PaletteArgb.cpp
// Copyright 2002 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/PaletteArgb.h"
#include "fileInterface/AbstractFile.h"
#include "sharedFile/TreeFile.h"
#include "sharedFoundation/ExitChain.h"
#include "sharedMath/PackedArgb.h"
#include "sharedMath/PaletteArgbList.h"
#include "sharedFoundation/MemoryBlockManager.h"
#include <limits>
#include <vector>
#include <cstdio>
// ======================================================================
bool PaletteArgb::ms_installed;
MemoryBlockManager *PaletteArgb::ms_memoryBlockManager;
// ======================================================================
/**
* Install the PaletteArgb class.
*
* This function call must be made prior to creating or using any
* PaletteArgb instances. As of this writing, this function call is
* invoked via SetupSharedMath::install(). The caller should ensure
* SetupSharedMath::install() is invoked in any application that will
* use PaletteArgb.
*
* @see SetupSharedMath::install().
*/
void PaletteArgb::install()
{
DEBUG_FATAL(ms_installed, ("PaletteArgb already installed"));
ms_memoryBlockManager = new MemoryBlockManager("PaletteArgb", true, sizeof(PaletteArgb), 0, 0, 0);
ms_installed = true;
ExitChain::add(remove, "PaletteArgb");
}
// ----------------------------------------------------------------------
/**
* Allocate storage for a new dynamically allocated PaletteArgb
* instance.
*
* PaletteArgb memory is managed by a MemoryBlockManager.
*/
void *PaletteArgb::operator new(size_t size)
{
DEBUG_FATAL(!ms_installed, ("PaletteArgb not installed"));
DEBUG_FATAL(size != sizeof(PaletteArgb), ("PaletteArgb::operator new() doesn't support allocation for child classes"));
UNREF(size);
return ms_memoryBlockManager->allocate();
}
// ----------------------------------------------------------------------
/**
* Free storage associated with a dynamically allocated PaletteArgb
* instance.
*
* PaletteArgb memory is managed by a MemoryBlockManager.
*/
void PaletteArgb::operator delete(void *data)
{
DEBUG_FATAL(!ms_installed, ("PaletteArgb not installed"));
if (data)
ms_memoryBlockManager->free(data);
}
// ======================================================================
/**
* Contruct a modifiable PaletteArgb instance supporting a specified
* number of palette entries.
*
* The number of palette entries handled by the palette may never
* change from the value provided in the constructor.
*
* Since callers using this interface do no go through the
* PaletteArgbList::fetch() interface, the caller must perform
* a fetch() on the instance after construction completes. When
* the caller is done with the instance, call release() to destroy
* it.
*
* @param entryCount the number of palette entries in the palette.
*/
PaletteArgb::PaletteArgb(int entryCount) :
m_name(),
m_referenceCount(0),
m_entries(new PackedArgbVector())
{
DEBUG_FATAL(!ms_installed, ("PaletteArgb not installed"));
if (entryCount >= 0)
m_entries->resize(static_cast<size_t>(entryCount));
else
DEBUG_WARNING(true, ("PaletteArgb::PaletteArgb() bad entryCount [%d]", entryCount));
}
// ----------------------------------------------------------------------
PaletteArgb::PaletteArgb(PackedArgbVector const & packedArgbVector) :
m_name(),
m_referenceCount(0),
m_entries(new PackedArgbVector(packedArgbVector.begin(), packedArgbVector.end()))
{
DEBUG_FATAL(!ms_installed, ("PaletteArgb not installed"));
}
// ----------------------------------------------------------------------
/**
* Release a reference to the PaletteArgb instance.
*
* PaletteArgb::fetch() should be called for each logical reference
* the caller has for the instance. When the logical reference is
* no longer needed, it should be released with a call to PackedArgb::release().
* When no more references exist to a given PaletteArgb, typically
* it is destroyed.
*
* Failure to fetch() a reference
*/
void PaletteArgb::release() const
{
if (m_referenceCount < 1)
{
//-- Trying to track down a fatal for live. We will fatal in optimized builds, but we want to gracefully handle release builds
DEBUG_WARNING(true, ("PaletteArgb::release(%s): faulty reference count handling, ref count is [%d].", getName().getString(), m_referenceCount));
}
else
{
--m_referenceCount;
//-- We are going to let the PaletteArgbList keep references to the palettes and clean them up at the end.
#if 0
if (m_referenceCount == 0)
{
PaletteArgbList::stopTracking(*this);
delete const_cast<PaletteArgb*>(this);
}
#endif
}
}
// ----------------------------------------------------------------------
/**
* Return the number of palette entries stored in the palette.
*
* @return the number of palette entries stored in the palette.
*/
int PaletteArgb::getEntryCount() const
{
return static_cast<int>(m_entries->size());
}
// ----------------------------------------------------------------------
/**
* Retrieve a const reference to the specified palette entry.
*
* The specified palette entry must be in the range of 0 (inclusive)
* through getEntryCount()-1 (inclusive). Debug builds will FATAL
* if the precondition is not met, while undefined behavior ensues
* in release builds.
*
* @param index 0-based index of palette entry to retrieve.
*
* @return const reference to the specified palette entry.
*
* @see getEntryCount()
* @see PackedArgb
*/
const PackedArgb &PaletteArgb::getEntry(int index, bool & error) const
{
return const_cast<PaletteArgb *>(this)->getEntry(index, error);
}
// ----------------------------------------------------------------------
/**
* Retrieve a modifiable reference to the specified palette entry.
*
* The specified palette entry must be in the range of 0 (inclusive)
* through getEntryCount()-1 (inclusive). Debug builds will FATAL
* if the precondition is not met, while undefined behavior ensues
* in release builds.
*
* @param index 0-based index of palette entry to retrieve.
*
* @return modifiable reference to the specified palette entry.
*
* @see getEntryCount()
* @see PackedArgb
*/
PackedArgb &PaletteArgb::getEntry(int index, bool & error)
{
error = false;
const int size = static_cast<int>(m_entries->size ());
if (index < 0 || index >= size)
{
error = true;
DEBUG_WARNING(true, ("Designer/Art bug: [%s] Invalid index %d for range [%d-%d), clamping to 0: update object template customization data.", m_name.getString (), index, 0, size));
index = 0;
}
return (*m_entries)[static_cast<size_t>(index)];
}
// ----------------------------------------------------------------------
/**
* Write the palette to a Microsoft Palette (r) PAL file.
*
* The specified pathName is a platform filesystem name.
*
* @param pathName the platform-specific filesystem name where the
* palette data will be written.
*
* @return true if the palette data was written successfully to
* the file; false otherwise.
*/
bool PaletteArgb::write(const char *pathName) const
{
//-- write palette data to a temp buffer
const int MAX_ENTRY_COUNT = 1024;
const int BUFFER_SIZE = MAX_ENTRY_COUNT * 4 + 24;
unsigned char buffer[BUFFER_SIZE];
int numberOfBytesWritten = 0;
if (!writeToBuffer(buffer, BUFFER_SIZE, numberOfBytesWritten))
{
WARNING(true, ("failed to write palette to temporary buffer."));
return false;
}
//-- write buffer to file
// open file
FILE *const file = fopen(pathName, "wb");
if (!file)
{
WARNING(true, ("failed to open file [%s] for writing.", pathName));
return false;
}
// write contents to file
const size_t unitsWritten = fwrite(buffer, static_cast<size_t>(numberOfBytesWritten), 1, file);
if (unitsWritten != 1)
{
WARNING(true, ("failed to write palette data (%d bytes) to file [%s].", numberOfBytesWritten, pathName));
return false;
}
// close file
IGNORE_RETURN(fclose(file));
//-- success
return true;
}
// ----------------------------------------------------------------------
/**
* Retrieve the index of the palette entry with a color that most closely
* matches the specified color.
*
* The algorithmic complexity of this function is O(n),
* where n = # entries in the palette.
*
* This function defines "closest color" to be the color with the minimum
* sum of squares separation from the target color.
*
* @return the index of the palette entry with a color that most closely
* matches the specified color. If the palette contains no entries,
* returns -1.
*/
int PaletteArgb::findClosestMatch(const PackedArgb &targetColor) const
{
NOT_NULL(m_entries);
int minValue = std::numeric_limits<int>::max();
int minIndex = -1;
const int tr = static_cast<int>(targetColor.getR());
const int tg = static_cast<int>(targetColor.getG());
const int tb = static_cast<int>(targetColor.getB());
const int ta = static_cast<int>(targetColor.getA());
int index = 0;
const PackedArgbVector::const_iterator endIt = m_entries->end();
for (PackedArgbVector::const_iterator it = m_entries->begin(); it != endIt; ++it, ++index)
{
//-- prevent excessive casting in sum of squares calculation
const int cr = static_cast<int>(it->getR());
const int cg = static_cast<int>(it->getG());
const int cb = static_cast<int>(it->getB());
const int ca = static_cast<int>(it->getA());
//-- compute sum of squares difference in color from target
const int value =
((cr - tr) * (cr - tr)) +
((cg - tg) * (cg - tg)) +
((cb - tb) * (cb - tb)) +
((ca - ta) * (ca - ta));
//-- check if we found the closest color
if (value < minValue)
{
minValue = value;
minIndex = index;
}
}
return minIndex;
}
// ======================================================================
void PaletteArgb::remove()
{
DEBUG_FATAL(!ms_installed, ("PaletteArgb not installed"));
delete ms_memoryBlockManager;
ms_memoryBlockManager = 0;
ms_installed = false;
}
// ======================================================================
PaletteArgb::PaletteArgb(const CrcString &pathName) :
m_name(pathName.getString(), true),
m_referenceCount(0),
m_entries(new PackedArgbVector())
{
DEBUG_FATAL(!ms_installed, ("PaletteArgb not installed"));
//-- load file contents
// open file
AbstractFile *const file = TreeFile::open(pathName.getString(), AbstractFile::PriorityData, false);
NOT_NULL(file);
// process file
load(*file);
delete file;
}
// ----------------------------------------------------------------------
PaletteArgb::~PaletteArgb()
{
delete m_entries;
}
// ----------------------------------------------------------------------
void PaletteArgb::load(AbstractFile &file)
{
const int MAX_ENTRY_COUNT = 1024;
const int BUFFER_SIZE = MAX_ENTRY_COUNT * 4 + 24;
unsigned char buffer[BUFFER_SIZE];
//-- load contents
// ensure file isn't too big
const int fileSize = file.length();
if (fileSize > BUFFER_SIZE)
{
WARNING(true, ("palette file [%s] too large, can't open, skipping data.", m_name.getString()));
return;
}
// ensure file isn't too small
if (fileSize < 24)
{
WARNING(true, ("palette file [%s] is too small to be a palette file, skipping data.", m_name.getString()));
return;
}
const int bytesRead = file.read(buffer, fileSize);
if (bytesRead != fileSize)
{
WARNING(true, ("palette file [%s] reported %d bytes, but only read %d bytes, skipping data.", m_name.getString(), fileSize, bytesRead));
return;
}
//-- verify header
int bufferPosition = 0;
// read RIFF FourCC
if (
(buffer[bufferPosition++] != 'R') ||
(buffer[bufferPosition++] != 'I') ||
(buffer[bufferPosition++] != 'F') ||
(buffer[bufferPosition++] != 'F'))
{
WARNING(true, ("palette file [%s] is missing RIFF header, skipping data.", m_name.getString()));
return;
}
// read RIFF chunk length (stored little-endian)
const uint riffLength =
(static_cast<uint>(buffer[bufferPosition + 0]) << 0) |
(static_cast<uint>(buffer[bufferPosition + 1]) << 8) |
(static_cast<uint>(buffer[bufferPosition + 2]) << 16) |
(static_cast<uint>(buffer[bufferPosition + 3]) << 24);
bufferPosition += 4;
// read 'PAL ' riff chunk designation
if (
(buffer[bufferPosition++] != 'P') ||
(buffer[bufferPosition++] != 'A') ||
(buffer[bufferPosition++] != 'L') ||
(buffer[bufferPosition++] != ' '))
{
WARNING(true, ("palette file [%s] is missing PAL riff data designation, skipping data.", m_name.getString()));
return;
}
//-- read palette data chunk
// read 'data' chunk FourCC
if (
(buffer[bufferPosition++] != 'd') ||
(buffer[bufferPosition++] != 'a') ||
(buffer[bufferPosition++] != 't') ||
(buffer[bufferPosition++] != 'a'))
{
WARNING(true, ("palette file [%s] is missing data chunk, skipping data.", m_name.getString()));
return;
}
// read palette chunk length
const uint paletteChunkLength =
(static_cast<uint>(buffer[bufferPosition + 0]) << 0) |
(static_cast<uint>(buffer[bufferPosition + 1]) << 8) |
(static_cast<uint>(buffer[bufferPosition + 2]) << 16) |
(static_cast<uint>(buffer[bufferPosition + 3]) << 24);
bufferPosition += 4;
const uint expectedRiffLength = paletteChunkLength + 12;
if (riffLength != expectedRiffLength)
{
WARNING(true, ("palette file [%s] riff chunk expected to be %u bytes, file says it is %u bytes, skipping data.", m_name.getString(), expectedRiffLength, riffLength));
return;
}
// read unknown byte (should be zero?)
const uint unknownPaletteValue01 = static_cast<uint>(buffer[bufferPosition++]);
if (unknownPaletteValue01 != 0)
{
WARNING(true, ("palette file [%s] has unknown palette value, usually 0, as [%u], just a warning.", m_name.getString(), unknownPaletteValue01));
}
// read palette component count or version # (3 is all test cases)
const uint versionOrComponentCount = static_cast<uint>(buffer[bufferPosition++]);
if (versionOrComponentCount != 3)
{
WARNING(true, ("palette file [%s] has component/version != 3 [%u], skipping data.", m_name.getString(), versionOrComponentCount));
return;
}
// read palette entry count
const uint entryCount =
(static_cast<uint>(buffer[bufferPosition + 0]) << 0) |
(static_cast<uint>(buffer[bufferPosition + 1]) << 8);
bufferPosition += 2;
if (static_cast<int>(entryCount) > MAX_ENTRY_COUNT)
{
WARNING(true, ("palette file [%s] has has %u entries, we support a max of %d, skipping data.", m_name.getString(), entryCount, MAX_ENTRY_COUNT));
return;
}
//-- do sanity checking on palette count vs. chunk size
const uint expectedPaletteChunkLength = 4 + entryCount * 4;
if (paletteChunkLength != expectedPaletteChunkLength)
{
WARNING(true, ("palette file [%s] palette chunk expected to be %u bytes, file says it is %u bytes, skipping data.", m_name.getString(), expectedPaletteChunkLength, paletteChunkLength));
return;
}
//-- load the data
m_entries->resize(static_cast<size_t>(entryCount));
for (uint i = 0; i < entryCount; ++i)
{
PackedArgb &entry = (*m_entries)[static_cast<size_t>(i)];
entry.setR(buffer[bufferPosition++]);
entry.setG(buffer[bufferPosition++]);
entry.setB(buffer[bufferPosition++]);
entry.setA(buffer[bufferPosition++]);
//-- assume this variable indicates the number of components
if (versionOrComponentCount != 4)
{
// no alpha component, set to full-on
entry.setA(255);
}
}
}
// ----------------------------------------------------------------------
bool PaletteArgb::writeToBuffer(unsigned char *buffer, int bufferSize, int &numberOfBytesWritten) const
{
const int entryCount = getEntryCount();
const int requiredBufferSize = 24 + 4 * entryCount;
if (bufferSize < requiredBufferSize)
{
WARNING(true, ("writeToBuffer(): requires buffer size of %d, caller bufferSize is %d.", requiredBufferSize, bufferSize));
return false;
}
//-- write riff
unsigned char *const initialBuffer = buffer;
// write RIFF
*(buffer++) = 'R';
*(buffer++) = 'I';
*(buffer++) = 'F';
*(buffer++) = 'F';
// write riff chunk length
const uint riffChunkLength = 16 + 4 * static_cast<uint>(entryCount);
*(buffer++) = static_cast<unsigned char>((riffChunkLength >> 0) & 0xff);
*(buffer++) = static_cast<unsigned char>((riffChunkLength >> 8) & 0xff);
*(buffer++) = static_cast<unsigned char>((riffChunkLength >> 16) & 0xff);
*(buffer++) = static_cast<unsigned char>((riffChunkLength >> 24) & 0xff);
// write PAL data designation
*(buffer++) = 'P';
*(buffer++) = 'A';
*(buffer++) = 'L';
*(buffer++) = ' ';
// write palette chunk FourCC
*(buffer++) = 'd';
*(buffer++) = 'a';
*(buffer++) = 't';
*(buffer++) = 'a';
// write palette chunk length
const uint paletteChunkLength = 4 + 4 * static_cast<uint>(entryCount);
*(buffer++) = static_cast<unsigned char>((paletteChunkLength >> 0) & 0xff);
*(buffer++) = static_cast<unsigned char>((paletteChunkLength >> 8) & 0xff);
*(buffer++) = static_cast<unsigned char>((paletteChunkLength >> 16) & 0xff);
*(buffer++) = static_cast<unsigned char>((paletteChunkLength >> 24) & 0xff);
// write unknown byte. I've only seen 0 coming out of Photoshop 6.0.
*(buffer++) = 0;
// write component count/version (not sure what this is, but is 3 coming out of Photoshop 6.0)
const uint componentCount = 3;
*(buffer++) = static_cast<unsigned char>(componentCount);
// write entry count
const uint uiEntryCount = static_cast<uint>(entryCount);
*(buffer++) = static_cast<unsigned char>((uiEntryCount >> 0) & 0xff);
*(buffer++) = static_cast<unsigned char>((uiEntryCount >> 8) & 0xff);
// write data
for (uint i = 0; i < uiEntryCount; ++i)
{
const PackedArgb &entry = (*m_entries)[static_cast<size_t>(i)];
*(buffer++) = entry.getR();
*(buffer++) = entry.getG();
*(buffer++) = entry.getB();
*(buffer++) = entry.getA();
}
//-- sanity check: make sure the calculated # bytes is the number of bytes written.
// if not, either I wrote the wrong data or calculated the size wrong.
numberOfBytesWritten = (buffer - initialBuffer);
DEBUG_FATAL(numberOfBytesWritten != requiredBufferSize, ("palette data write failure, should have written %d bytes, wrote %d bytes.", requiredBufferSize, numberOfBytesWritten));
// success
return true;
}
// ======================================================================
@@ -0,0 +1,163 @@
// ======================================================================
//
// PaletteArgb.h
// Copyright 2002 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_PaletteArgb_H
#define INCLUDED_PaletteArgb_H
// ======================================================================
class AbstractFile;
class PackedArgb;
class PaletteArgbList;
class MemoryBlockManager;
#include "sharedFoundation/PersistentCrcString.h"
// ======================================================================
/**
* Provides for loading, manipulation and saving of color palette
* data.
*
* Color palette data may be read from and written to the
* Microsoft Palette (r) format, typically stored with the .PAL
* file extension. Adobe Photoshop can load and save .PAL files.
*
* The palette may have as few as zero entries or as many as
* 1024 entries. The upper limit on palette entry count is
* fixed by the file format at 65535 entries (2^32-1); however,
* for implementation efficiency this class only supports a
* maximum of 1024 entries. The size of palette data in the .PAL file
* is linearly related to the number of palette entries,
* 24 bytes + 4 * (# palette entries).
*
* PaletteArgb loading is accomplished via the PaletteArgbList
* class. The caller may not modify a loaded PaletteArgb instance.
*
* PaletteArgb instances may be created and modified via the public
* constructor. Currently the caller must specify the exact number
* of palette entries at time of construction. PaletteArgb supports
* writing to a file via the PaletteArgb::write() function.
*/
class PaletteArgb
{
friend class PaletteArgbList;
public:
static void install();
static void *operator new(size_t size);
static void operator delete(void *data);
public:
explicit PaletteArgb(int entryCount);
explicit PaletteArgb(stdvector<PackedArgb>::fwd const & packedArgbVector);
const CrcString &getName() const;
void fetch() const;
void release() const;
int getReferenceCount() const;
int getEntryCount() const;
const PackedArgb &getEntry(int index, bool & error) const;
PackedArgb &getEntry(int index, bool & error);
bool write(const char *pathName) const;
int findClosestMatch(const PackedArgb &targetColor) const;
private:
typedef stdvector<PackedArgb>::fwd PackedArgbVector;
private:
static void remove();
private:
PaletteArgb(const CrcString &pathName);
~PaletteArgb();
void load(AbstractFile &file);
bool writeToBuffer(unsigned char *buffer, int bufferSize, int &numberOfBytesWritten) const;
// disabled
PaletteArgb();
PaletteArgb(const PaletteArgb&);
PaletteArgb &operator =(const PaletteArgb&);
private:
static bool ms_installed;
static MemoryBlockManager *ms_memoryBlockManager;
private:
PersistentCrcString m_name;
mutable int m_referenceCount;
PackedArgbVector *const m_entries;
};
// ======================================================================
/**
* Return the pathname of the PaletteArgb instance.
*
* The pathname for the instance will be a non-zero-length string only
* if the PaletteArgb instance was loaded via PaletteArgbList.
*
* @return the pathname of the PaletteArgb if loaded; otherwise,
* zero-length string.
*
* @see PaletteArgbList
*/
inline const CrcString &PaletteArgb::getName() const
{
return m_name;
}
// ----------------------------------------------------------------------
/**
* Release a reference to the PaletteArgb instance.
*
* PaletteArgb::fetch() should be called for each logical reference
* the caller has for the instance. When the logical reference is
* no longer needed, it should be released with a call to PackedArgb::release().
* When no more references exist to a given PaletteArgb, typically
* it is destroyed.
*
* Failure to fetch() a reference
*/
inline void PaletteArgb::fetch() const
{
++m_referenceCount;
}
// ----------------------------------------------------------------------
/**
* Return the number of logical references existing on this
* PaletteArgb instance.
*
* @return the number of logical references existing on this
* PaletteArgb instance.
*/
inline int PaletteArgb::getReferenceCount() const
{
return m_referenceCount;
}
// ======================================================================
#endif
@@ -0,0 +1,242 @@
// ======================================================================
//
// PaletteArgbList.cpp
// Copyright 2002 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/PaletteArgbList.h"
#include "sharedFile/AsynchronousLoader.h"
#include "sharedFile/TreeFile.h"
#include "sharedFoundation/ExitChain.h"
#include "sharedFoundation/LessPointerComparator.h"
#include "sharedFoundation/TemporaryCrcString.h"
#include "sharedMath/PackedArgb.h"
#include "sharedMath/PaletteArgb.h"
#include "sharedSynchronization/Mutex.h"
#include <map>
// ======================================================================
namespace PaletteArgbListNamespace
{
Mutex s_criticalSection;
}
using namespace PaletteArgbListNamespace;
// ======================================================================
bool PaletteArgbList::ms_installed;
PaletteArgbList::ResourceMap *PaletteArgbList::ms_resourceMap;
// ======================================================================
/**
* Install the PaletteArgbList.
*
* This function must be invoked prior to using any
* other aspect of the PaletteArgbList class. As of this writing,
* PaletteArgbList::install() is invoked via SetupSharedMath::install().
*
* @see SetupSharedMath.
*/
void PaletteArgbList::install()
{
DEBUG_FATAL(ms_installed, ("PaletteArgbList already installed"));
ms_resourceMap = new ResourceMap();
ms_installed = true;
ExitChain::add(remove, "PaletteArgbList");
}
// ----------------------------------------------------------------------
/**
* Retrieve a PaletteArgb instance loaded from the specified filename.
*
* The specified pathName is the path to the Microsoft Palette (r) (.PAL)
* file to load via the TreeFile System. If the given file currently
* is loaded, the same instance with a bumped up reference count will
* be returned.
*
* This function bumps up the reference count on the returned instance.
* When the caller is done with the PaletteArgb, it should call
* PaletteArgb::release().
*
* If the specfied filename can not be found, a default palette with
* one all-zero entry will be returned along with a WARNING.
*
* @param pathName TreeFile-accessible pathname to a Microsoft Palette (r)
* file.
*
* @return the contents of the Palette file if the palette file
* exists; otherwise, a default palette instance.
*
* @see PaletteArgb::release().
*/
const PaletteArgb *PaletteArgbList::fetch(const CrcString &pathName)
{
return fetch(pathName, true);
}
// ----------------------------------------------------------------------
void PaletteArgbList::assignAsynchronousLoaderFunctions()
{
if (AsynchronousLoader::isInstalled())
AsynchronousLoader::bindFetchReleaseFunctions("pal", &asynchronousLoaderFetchNoCreate, &asynchronousLoaderRelease);
}
// ======================================================================
void PaletteArgbList::remove()
{
DEBUG_FATAL(!ms_installed, ("PaletteArgbList not installed"));
//-- release exisitng palettes, report memory leaks
//DEBUG_REPORT_LOG(!ms_resourceMap->empty(), ("PaletteArgbList: loaded [%u] palettes:", ms_resourceMap->size()));
const ResourceMap::iterator endIt = ms_resourceMap->end();
for (ResourceMap::iterator it = ms_resourceMap->begin(); it != endIt; ++it)
{
PaletteArgb const * palette = it->second;
// print leak info
NOT_NULL(palette);
DEBUG_WARNING(palette->getReferenceCount() > 0, (" palette [%s]: %d references outstanding", it->first->getString(), palette->getReferenceCount()));
// delete the resource
delete palette;
}
//-- delete the map
delete ms_resourceMap;
ms_resourceMap = 0;
ms_installed = false;
}
// ----------------------------------------------------------------------
void PaletteArgbList::stopTracking(const PaletteArgb &palette)
{
DEBUG_FATAL(!ms_installed, ("PaletteArgbList not installed"));
s_criticalSection.enter();
//-- check if this palette is named. if not, ignore it.
const char *const paletteName = palette.getName().getString();
if (!paletteName || !*paletteName)
{
// palette has no name, so the list isn't tracking it.
s_criticalSection.leave();
return;
}
//-- find it in our list.
const ResourceMap::iterator findIt = ms_resourceMap->find(&palette.getName());
if (findIt == ms_resourceMap->end())
{
// not found
DEBUG_WARNING(true, ("named palette [%s] not tracked, shouldn't happen.", palette.getName().getString()));
}
else
{
// found it
ms_resourceMap->erase(findIt);
}
s_criticalSection.leave();
}
// ----------------------------------------------------------------------
const void *PaletteArgbList::asynchronousLoaderFetchNoCreate(char const *fileName)
{
TemporaryCrcString cfn(fileName, true);
return PaletteArgbList::fetch(cfn, false);
}
// ----------------------------------------------------------------------
void PaletteArgbList::asynchronousLoaderRelease(void const *palette)
{
static_cast<PaletteArgb const *>(palette)->release();
}
// ----------------------------------------------------------------------
const PaletteArgb *PaletteArgbList::fetch(const CrcString &pathName, bool create)
{
DEBUG_FATAL(!ms_installed, ("PaletteArgbList not installed"));
s_criticalSection.enter();
//-- check if the pathName is cached
const ResourceMap::iterator lowerBoundResult = ms_resourceMap->lower_bound(&pathName);
const bool haveResource = ((lowerBoundResult != ms_resourceMap->end()) && !ms_resourceMap->key_comp()(&pathName, lowerBoundResult->first));
if (haveResource)
{
NOT_NULL(lowerBoundResult->second);
lowerBoundResult->second->fetch();
PaletteArgb const *const palette = lowerBoundResult->second;
s_criticalSection.leave();
return palette;
}
// resource doesn't exist
//-- Skip if not creating.
if (!create)
{
s_criticalSection.leave();
return 0;
}
PaletteArgb *palette = 0;
//-- check if referenced filename exists
if (!TreeFile::exists(pathName.getString()))
{
//-- palette file can't be found, return a new default palette.
// note: this palette doesn't get mapped, so every call for this
// non-existent palette will generate a new one. That's okay,
// this should be a rare occurrence. If it is not rare and acceptable,
// we'll want a single default palette allocated and returned.
WARNING(true, ("palette [%s] not found, using default palette.", pathName.getString()));
palette = new PaletteArgb(1);
// Set only color to something we can tell is a bug.
bool error = false;
PackedArgb &entry = palette->getEntry(0, error);
WARNING(error, ("PaletteArgbList::fetch error"));
entry.setArgb(255, 0, 255, 255);
}
else
{
//-- palette file found, load it
palette = new PaletteArgb(pathName);
//-- map resource to name
IGNORE_RETURN(ms_resourceMap->insert(lowerBoundResult, ResourceMap::value_type(&palette->getName(), palette)));
}
//-- bump up the reference count
NOT_NULL(palette);
palette->fetch();
s_criticalSection.leave();
return palette;
}
// ======================================================================
@@ -0,0 +1,63 @@
// ======================================================================
//
// PaletteArgbList.h
// Copyright 2002 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_PaletteArgbList_H
#define INCLUDED_PaletteArgbList_H
// ======================================================================
class CrcString;
class LessPointerComparator;
class PaletteArgb;
// ======================================================================
/**
* Manages PaletteArgb assets loaded via the TreeFile system.
*
* The PaletteArgbList coordinates handing out reference-counted
* PaletteArgb instances loaded from the TreeFile system. It ensures
* only a single instance of a Palette file is loaded at any given time.
*/
class PaletteArgbList
{
friend class PaletteArgb;
public:
static void install();
static const PaletteArgb *fetch(const CrcString &pathName);
static void assignAsynchronousLoaderFunctions();
private:
typedef stdmap<const CrcString *, PaletteArgb*, LessPointerComparator>::fwd ResourceMap;
private:
static void remove();
static void stopTracking(const PaletteArgb &palette);
static const void *asynchronousLoaderFetchNoCreate(char const *fileName);
static void asynchronousLoaderRelease(void const *palette);
static const PaletteArgb *fetch(const CrcString &pathName, bool create);
private:
static bool ms_installed;
static ResourceMap *ms_resourceMap;
};
// ======================================================================
#endif
@@ -0,0 +1,371 @@
// ======================================================================
//
// Plane.cpp
// jeff grills
//
// copyright 1998 Bootprint Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Plane.h"
#include "sharedMath/Transform.h"
// ======================================================================
// Construct a plane given three non-colinear points
//
// Remarks:
//
// The front half of the plane is the side from which the vertices would
// be specified in a clockwise order.
Plane::Plane(
const Vector &point0, // [IN] First point on the plane
const Vector &point1, // [IN] Second point on the plane
const Vector &point2 // [IN] Third point on the plane
)
: normal(),
d(CONST_REAL(0))
{
set(point0, point1, point2);
}
// ----------------------------------------------------------------------
/**
* Define a plane given three non-colinear points.
*
* The front half of the plane is the side from which the vertices would
* be specified in a clockwise order.
*
* @param point0 [IN] First point on the plane
* @param point1 [IN] Second point on the plane
* @param point2 [IN] Third point on the plane
*/
void Plane::set(const Vector &point0, const Vector &point1, const Vector &point2)
{
// calculate the new normal direction
normal = (point0 - point2).cross(point1 - point0);
// normalize the normal
if (!normal.normalize())
{
normal = Vector::unitZ;
DEBUG_WARNING(true, ("Plane::calculate could not normalize vector"));
}
// compute the plane D coefficient
d = -normal.dot(point0);
}
// ----------------------------------------------------------------------
/**
* Find the intersection between a line segment and the plane.
*
* If the line segment does intersect the plane, and the intersection
* pointer is non-NULL, then intersection will be set to the point on
* the line segment that crosses the plane.
*
* @param point0 [IN] Start of the line segment
* @param point1 [IN] End of the line segment
* @return True if the line segment intersects the plane, otherwise false.
*/
bool Plane::findIntersection(const Vector &point0, const Vector &point1) const
{
const real t0(computeDistanceTo(point0));
const real t1(computeDistanceTo(point1));
// check to make sure the endpoints span the plane
return (t0 * t1) < 0; // if either is zero, the point is on the plane
}
// ----------------------------------------------------------------------
/**
* Find the intersection between a line segment and the plane.
*
* If the line segment does intersect the plane, and the intersection
* pointer is non-NULL, then intersection will be set to the point on
* the line segment that crosses the plane.
*
* @param point0 [IN] Start of the line segment
* @param point1 [IN] End of the line segment
* @param intersection [OUT] Intersection of the point and the plane
* @return True if the line segment intersects the plane, otherwise false.
*/
bool Plane::findIntersection(const Vector &point0, const Vector &point1, Vector &intersection) const
{
const real t0(computeDistanceTo(point0));
const real t1(computeDistanceTo(point1));
// check to make sure the endpoints span the plane
if ((t0 * t1) > CONST_REAL(0))
return false;
if (t0 == t1) // both zero
{
intersection = point1;
return true;
}
float abst = t0 / (t0 - t1); // safe since sign of t0 is always opposite t1
intersection = Vector::linearInterpolate(point0, point1, abst);
return true;
}
// ----------------------------------------------------------------------
/**
* Find the intersection between a line segment and the plane.
*
* If the line segment does intersect the plane, and the intersection
* pointer is non-NULL, then intersection will be set to the point on
* the line segment that crosses the plane.
*
* @param point0 [IN] Start of the line segment
* @param point1 [IN] End of the line segment
* @param intersection [OUT] Intersection of the point and the plane
* @param t [OUT] parameterized t from 0..1
* @return True if the line segment intersects the plane, otherwise false.
*/
bool Plane::findIntersection(const Vector &point0, const Vector &point1, Vector &intersection, float &t) const
{
const real t0(computeDistanceTo(point0));
const real t1(computeDistanceTo(point1));
// check to make sure the endpoints span the plane
if ((t0 * t1) > CONST_REAL(0))
return false;
if (t0 == t1) // both zero
{
intersection = point0;
t=0;
return true;
}
float abst = t0 / (t0 - t1); // safe since sign of t0 is always opposite t1
intersection = Vector::linearInterpolate(point0, point1, abst);
t = abst;
return true;
}
// ----------------------------------------------------------------------
/**
* Find the intersection between a line segment and the plane.
*
* If the line segment does intersect the plane, and the intersection
* pointer is non-NULL, then intersection will be set to the point on
* the line segment that crosses the plane.
*
* @param point0 [IN] Start of the line segment
* @param point1 [IN] End of the line segment
* @param intersection [OUT] Intersection of the point and the plane
* @param t [OUT] parameterized t from 0..1
* @return True if the line segment intersects the plane, otherwise false.
*/
bool Plane::findIntersection(const Vector &point0, const Vector &point1, float &t) const
{
const real t0(computeDistanceTo(point0));
const real t1(computeDistanceTo(point1));
// check to make sure the endpoints span the plane
if ((t0 * t1) > CONST_REAL(0))
return false;
if (t0 == t1) // both zero
{
t=0;
return true;
}
t = t0 / (t0 - t1); // safe since sign of t0 is always opposite t1
return true;
}
// ----------------------------------------------------------------------
/**
* Find the directed intersection between a line segment and the plane.
*
* This routine will only detect the intersection if point0
* is on the front side of the plane, and point1 is on the
* back side of the plane.
*
* If the line segment does intersect the plane, and the intersection
* pointer is non-NULL, then intersection will be set to the point on
* the line segment that crosses the plane.
*
* @param point0 [IN] Start of the line segment
* @param point1 [IN] End of the line segment
* @return True if the line segment intersects the plane from front-to-rear, otherwise false.
*/
bool Plane::findDirectedIntersection(const Vector &point0, const Vector &point1) const
{
const real t0(computeDistanceTo(point0));
const real t1(computeDistanceTo(point1));
// check to make t0 is on the front side of the plane and t1 is on the back side of the plane
return !((t0 < CONST_REAL(0) || t1 > CONST_REAL(0)));
}
// ----------------------------------------------------------------------
/**
* Find the directed intersection between a line segment and the plane.
*
* This routine will only detect the intersection if point0
* is on the front side of the plane, and point1 is on the
* back side of the plane.
*
* If the line segment does intersect the plane, and the intersection
* pointer is non-NULL, then intersection will be set to the point on
* the line segment that crosses the plane.
*
* @param point0 [IN] Start of the line segment
* @param point1 [IN] End of the line segment
* @param intersection [OUT] Intersection of the point and the plane (may be NULL)
* @param t [OUT] parameterized t from 0..1
* @return True if the line segment intersects the plane from front-to-rear, otherwise false.
*/
bool Plane::findDirectedIntersection(const Vector &point0, const Vector &point1, Vector &intersection) const
{
const real t0(computeDistanceTo(point0));
const real t1(computeDistanceTo(point1));
// check to make t0 is on the front side of the plane and t1 is on the back side of the plane
if (t0 < CONST_REAL(0) || t1 > CONST_REAL(0))
return false;
if (t0 == t1) // both zero
{
intersection = point1;
return true;
}
// solve parametric equation to find the intersection point
float abst = t0 / (t0 - t1); // safe sine sign of t0 is always opposite t1
intersection = Vector::linearInterpolate(point0, point1, abst);
return true;
}
// ----------------------------------------------------------------------
/**
* Find the directed intersection between a line segment and the plane.
*
* This routine will only detect the intersection if point0
* is on the front side of the plane, and point1 is on the
* back side of the plane.
*
* If the line segment does intersect the plane, and the intersection
* pointer is non-NULL, then intersection will be set to the point on
* the line segment that crosses the plane.
*
* @param point0 [IN] Start of the line segment
* @param point1 [IN] End of the line segment
* @param intersection [OUT] Intersection of the point and the plane (may be NULL)
* @param t [OUT] parameterized t from 0..1
* @return True if the line segment intersects the plane from front-to-rear, otherwise false.
*/
bool Plane::findDirectedIntersection(const Vector &point0, const Vector &point1, Vector &intersection, real &t) const
{
const real t0(computeDistanceTo(point0));
const real t1(computeDistanceTo(point1));
// check to make t0 is on the front side of the plane and t1 is on the back side of the plane
if (t0 < CONST_REAL(0) || t1 > CONST_REAL(0))
return false;
if (t0 == t1) // both zero
{
intersection = point0;
t=0;
return true;
}
// solve parametric equation to find the intersection point
float abst = t0 / (t0 - t1); // safe sine sign of t0 is always opposite t1
t = abst;
intersection = Vector::linearInterpolate(point0, point1, abst);
return true;
}
// ----------------------------------------------------------------------
/**
* Find the directed intersection between a line segment and the plane.
*
* This routine will only detect the intersection if point0
* is on the front side of the plane, and point1 is on the
* back side of the plane.
*
* If the line segment does intersect the plane, and the intersection
* pointer is non-NULL, then intersection will be set to the point on
* the line segment that crosses the plane.
*
* @param point0 [IN] Start of the line segment
* @param point1 [IN] End of the line segment
* @param intersection [OUT] Intersection of the point and the plane (may be NULL)
* @param t [OUT] parameterized t from 0..1
* @return True if the line segment intersects the plane from front-to-rear, otherwise false.
*/
bool Plane::findDirectedIntersection(const Vector &point0, const Vector &point1, real &t) const
{
const real t0(computeDistanceTo(point0));
const real t1(computeDistanceTo(point1));
// check to make t0 is on the front side of the plane and t1 is on the back side of the plane
if (t0 < CONST_REAL(0) || t1 > CONST_REAL(0))
return false;
if (t0 == t1) // both zero
{
t=0;
return true;
}
// solve parametric equation to find the intersection point
float abst = t0 / (t0 - t1); // safe sine sign of t0 is always opposite t1
t = abst;
return true;
}
// ----------------------------------------------------------------------
/**
* Transform the plane by the specified transformation
*
* @param trans the transformation to apply.
*/
void Plane::transform (const Transform & trans)
{
Vector const & p = trans.rotateTranslate_l2p (normal * -d);
normal = trans.rotate_l2p (normal);
d = computeD (normal, p);
}
// ----------------------------------------------------------------------
/**
* Transform the plane by the specified transformation
*
* @param trans the transformation to apply.
*/
void Plane::transform_p2l(const Transform &trans)
{
Vector const & p = trans.rotateTranslate_p2l(normal * -d);
normal = trans.rotate_p2l(normal);
d = computeD (normal, p);
}
// ======================================================================
@@ -0,0 +1,245 @@
// ======================================================================
//
// Plane.h
// jeff grills
//
// copyright 1998 Bootprint Entertainment
//
// ======================================================================
#ifndef PLANE_H
#define PLANE_H
// ======================================================================
#include "sharedMath/Vector.h"
class Transform;
// ======================================================================
// Class to contain data about a plane.
//
// The plane is described as a normal {A,B,C} and a D plane coefficient
// making the following equation true: Ax + By + Cz + D = 0.
class Plane
{
private:
// The plane's normal
Vector normal;
// The plane's D coefficient
real d;
public:
Plane(void);
Plane(const Vector &newNormal, real newD);
Plane(const Vector &point0, const Vector &point1, const Vector &point2);
Plane(const Vector &normal, const Vector &pointOnPlane);
void set(const Vector &newNormal, real newD);
void set(const Vector &point0, const Vector &point1, const Vector &point2);
void set(const Vector &newNormal, const Vector &pointOnPlane);
void set(const Plane &other, const Transform &trans);
void transform (const Transform &trans);
void transform_p2l(const Transform &trans);
const Vector &getNormal(void) const;
const real getD(void) const;
real computeDistanceTo(const Vector &point) const;
bool findIntersection(const Vector &point0, const Vector &point1) const;
bool findIntersection(const Vector &point0, const Vector &point1, Vector &intersection) const;
bool findIntersection(const Vector &point0, const Vector &point1, Vector &intersection, real &t) const;
bool findIntersection(const Vector &point0, const Vector &point1, real &t) const;
bool findDirectedIntersection(const Vector &point0, const Vector &point1) const;
bool findDirectedIntersection(const Vector &point0, const Vector &point1, Vector &intersection) const;
bool findDirectedIntersection(const Vector &point0, const Vector &point1, Vector &intersection, real &t) const;
bool findDirectedIntersection(const Vector &point0, const Vector &point1, real &t) const;
const Vector project(const Vector& point) const;
static real computeD(const Vector &normal, const Vector &point);
};
// ======================================================================
// Compute the plane d coefficient
//
// Return value:
//
// Plane D coefficient
//
// Remarks:
//
// d = -(ax + by + cz) = -(normal dot point)
inline real Plane::computeD(const Vector &norm, const Vector &point)
{
return -norm.dot(point);
}
// ----------------------------------------------------------------------
/**
* Construct a plane.
*
* The default plane will be pointed down the position Z axis, and be located
* at the origin.
*/
inline Plane::Plane(void)
: normal(Vector::unitZ),
d(CONST_REAL(0))
{
}
// ----------------------------------------------------------------------
/**
* Construct a plane.
*
* This routine constructs a plane with the specified normal and D-plane coefficient.
*
* @param newNormal [IN] Normal for the plane
* @param newD [IN] D-plane coefficient for the plane
*/
inline Plane::Plane(const Vector &newNormal, real newD)
: normal(newNormal),
d(newD)
{
}
// ----------------------------------------------------------------------
/**
* Construct a plane.
*
* This routine constructs a plane with the specified normal. The point
* on the plane is used to calculate the D-plane coefficient.
*
* @param newNormal [IN] Normal for the plane
* @param point [IN] Point on the plane
*/
inline Plane::Plane(const Vector &newNormal, const Vector &point)
: normal(newNormal),
d(computeD(newNormal, point))
{
}
// ----------------------------------------------------------------------
/**
* Set a plane.
*
* This routine sets the plane to have the specified normal and D-plane coefficient.
*
* @param newNormal [IN] Normal for the plane
* @param newD [IN] D-plane coefficient for the plane
*/
inline void Plane::set(const Vector &newNormal, real newD)
{
normal = newNormal;
d = newD;
}
// ----------------------------------------------------------------------
/**
* Set a plane.
*
* This routine sets the plane to have the specified normal and D-plane coefficient.
*
* @param newNormal [IN] Normal for the plane
* @param point [IN] Point on the plane
*/
inline void Plane::set(const Vector& newNormal, const Vector& point)
{
normal = newNormal;
d = computeD(normal, point);
}
// ----------------------------------------------------------------------
/**
* Compute the signed distance from the point to the plane.
*
* If the result is 0, the point is on the plane. If the result is positive,
* the point is on the front half-space of the plane. If the result is
* negative, the point is on the back half-space of the plane.
*
* @param point [IN] Point to test against the plane
* @return Signed distance from the point to the plane.
*/
inline real Plane::computeDistanceTo(const Vector &point) const
{
return normal.dot(point) + d;
}
// ----------------------------------------------------------------------
/**
* Get the plane's normal.
*
* The normal will be a unit vector pointing orthogonal to the plane.
*
* @return Normal for the plane
*/
inline const Vector &Plane::getNormal(void) const
{
return normal;
}
// ----------------------------------------------------------------------
/**
* Get the plane's D coefficient.
*
* The D coefficient if the value that makes the plane equation true,
* given XYZ as the plane's normal: X * x + Y * y + Z * z + D = 0.
* This value also represents the minimum distance from the origin to
* the plane.
*
* @return The D coefficient for the plane
*/
inline const real Plane::getD(void) const
{
return d;
}
// ----------------------------------------------------------------------
/**
* Find point projected onto the plane.
*
* @return The projected point onto the plane.
*/
inline const Vector Plane::project(const Vector &point) const
{
return point - (normal * computeDistanceTo(point));
}
// ----------------------------------------------------------------------
/**
* Set the value of this plane to be that of ther other with the specified transformation applied.
*
* @param other the other plane
* @param trans the transformation to be applied.
*/
inline void Plane::set (const Plane & other, const Transform & trans)
{
normal = other.normal;
d = other.d;
transform (trans);
}
// ======================================================================
#endif
@@ -0,0 +1,319 @@
// Polynomial solver code adapted from Graphics Gems version
// by Jochen Schwarze
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/PolySolver.h"
#include <math.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
double cuberoot( double x )
{
return ((x) > 0.0 ? pow(x, 1.0/3.0) : ((x) < 0.0 ? -pow(-x, 1.0/3.0) : 0.0));
}
int PolySolver::solveQuadratic( double const c[3], double s[2] )
{
double p, q, D;
/* normal form: x^2 + px + q = 0 */
p = c[ 1 ] / (2 * c[ 2 ]);
q = c[ 0 ] / c[ 2 ];
D = p * p - q;
if (D < 0)
{
return 0;
}
else
{
double sqrt_D = sqrt(D);
s[ 0 ] = sqrt_D - p;
s[ 1 ] = - sqrt_D - p;
return 2;
}
}
int PolySolver::solveCubic( double const c[4], double s[3] )
{
int i, num;
double sub;
double A, B, C;
double sq_A, p, q;
double cb_p, D;
/* normal form: x^3 + Ax^2 + Bx + C = 0 */
A = c[ 2 ] / c[ 3 ];
B = c[ 1 ] / c[ 3 ];
C = c[ 0 ] / c[ 3 ];
/* substitute x = y - A/3 to eliminate quadric term:
x^3 +px + q = 0 */
sq_A = A * A;
p = (1.0/3) * (- (1.0/3) * sq_A + B);
q = (1.0/2) * (((2.0/27) * A * sq_A - ((1.0/3) * A * B)) + C);
/* use Cardano's formula */
cb_p = p * p * p;
D = q * q + cb_p;
if (D < 0) /* Casus irreducibilis: three real solutions */
{
double phi = (1.0/3) * acos(-q / sqrt(-cb_p));
double t = 2 * sqrt(-p);
s[ 0 ] = t * cos(phi);
s[ 1 ] = - t * cos(phi + M_PI / 3);
s[ 2 ] = - t * cos(phi - M_PI / 3);
num = 3;
}
else /* one real solution */
{
double sqrt_D = sqrt(D);
double u = cuberoot(sqrt_D - q);
double v = - cuberoot(sqrt_D + q);
s[ 0 ] = u + v;
num = 1;
}
/* resubstitute */
sub = (1.0/3) * A;
for (i = 0; i < num; ++i)
s[ i ] -= sub;
return num;
}
double cubicError = 0.0f;
double cleanedCubicError = 0.0f;
double quarticError = 0.0f;
double cleanedQuarticError = 0.0f;
double evaluateCubic( double x, const double c[4] )
{
return ((x*c[3] + c[2]) * x + c[1]) * x + c[0];
}
double evaluateCubicDerivative ( double x, const double c[4] )
{
return (3.0*x + 2.0*c[2]) * x + c[1];
}
double cleanCubicRoot( double x, const double c[4] )
{
double e;
e = evaluateCubic(x,c);
if(fabs(e) > cubicError) cubicError = e;
// ----------
// for(int i = 0; i < 10; i++)
{
e = evaluateCubic(x,c);
e *= 0.8;
double d = evaluateCubicDerivative(x,c);
if(d != 0.0)
{
x = x - e/d;
}
}
// ----------
e = evaluateCubic(x,c);
if(fabs(e) > cleanedCubicError) cleanedCubicError = e;
return x;
}
double evaluateQuartic( double x, const double c[5] )
{
return (((x*c[4] + c[3]) * x + c[2]) * x + c[1]) * x + c[0];
}
double evaluateQuarticDerivative ( double x, const double c[5] )
{
return ((4.0*x*c[4] + 3.0*c[3]) * x + 2.0*c[2]) * x + c[1];
}
double cleanQuarticRoot( double x, const double c[4] )
{
double e;
e = evaluateQuartic(x,c);
if(fabs(e) > quarticError) quarticError = e;
// ----------
// for(int i = 0; i < 10; i++)
{
e = evaluateQuartic(x,c);
e *= 0.8;
double d = evaluateQuarticDerivative(x,c);
if(d != 0.0)
{
x = x - e/d;
}
}
// ----------
e = evaluateQuartic(x,c);
if(fabs(e) > cleanedQuarticError) cleanedQuarticError = e;
return x;
}
#ifdef WIN32
#define isnan(a) _isnan(a)
#endif
int PolySolver::solveQuartic( const double c[5], double s[4] )
{
double a3 = c[3] / c[4];
double a2 = c[2] / c[4];
double a1 = c[1] / c[4];
double a0 = c[0] / c[4];
// ----------
// solve the resolvent cubic to get a real root
double y1 = 1.0f;
{
double c[4];
c[3] = 1.0;
c[2] = -a2;
c[1] = (a1*a3) - (4.0)*(a0);
c[0] = (4.0)*(a2*a0) - (a1*a1) - (a3*a3*a0);
double s[3];
int nRoots = PolySolver::solveCubic(c,s);
for(int i = 0; i < nRoots; i++)
{
if(s[i] == s[i])
{
// root is real
y1 = cleanCubicRoot( s[i], c );
break;
}
}
}
// ----------
// use the root to find the roots of the quadric
double t1 = (1.0/4.0)*(a3*a3) - a2 + y1;
double R = sqrt(t1);
double D;
if(R == 0.0)
{
double t1 = (y1*y1) - (4.0)*(a0);
double t2 = sqrt(t1);
double t3 = (3.0/4.0)*(a3*a3) - (2.0)*(a2) + (2.0)*t2;
D = sqrt(t3);
}
else
{
double t1 = (4.0)*(a3*a2) - (8.0)*(a1) - (a3*a3*a3);
double t2 = t1 / (4.0 * R);
double t3 = (3.0/4.0)*(a3*a3) - (R*R) - (2.0)*(a2) + t2;
D = sqrt(t3);
}
double E;
if(R == 0.0)
{
double t1 = (y1*y1) - (4.0)*(a0);
double t2 = sqrt(t1);
double t3 = (3.0/4.0)*(a3*a3) - (2.0)*(a2) - (2.0)*(t2);
E = sqrt(t3);
}
else
{
double t1 = (4.0)*(a3*a2) - (8.0)*(a1) - (a3*a3*a3);
double t2 = t1 / (4.0 * R);
double t3 = (3.0/4.0)*(a3*a3) - (R*R) - (2.0)*(a2) - t2;
E = sqrt(t3);
}
static const double nan = sqrt(-1.0f);
if (isnan(D))
{
s[0] = nan;
s[1] = nan;
}
else
{
s[0] = (-1.0/4.0)*a3 + (1.0/2.0)*R + (1.0/2.0)*D;
s[1] = (-1.0/4.0)*a3 + (1.0/2.0)*R - (1.0/2.0)*D;
}
if (isnan(E))
{
s[2] = nan;
s[3] = nan;
}
else
{
s[2] = (-1.0/4.0)*a3 - (1.0/2.0)*R + (1.0/2.0)*E;
s[3] = (-1.0/4.0)*a3 - (1.0/2.0)*R - (1.0/2.0)*E;
}
/*
// Perform one step of a Newton iteration in order to minimize round-off errors
int i;
for(i = 0; i < 4; i++)
{
s[i] = cleanQuarticRoot(s[i],c);
}
*/
return 4;
}
@@ -0,0 +1,26 @@
// ======================================================================
//
// PolySolver.h
// copyright (c) 2001 Sony Online Entertainment
//
// ----------------------------------------------------------------------
#ifndef INCLUDED_PolySolver_H
#define INCLUDED_PolySolver_H
// ----------------------------------------------------------------------
class PolySolver
{
public:
static int solveQuadratic ( double const c[3], double r[2] );
static int solveCubic ( double const c[4], double r[3] );
static int solveQuartic ( double const c[5], double r[4] );
};
// ----------------------------------------------------------------------
#endif // #ifndef INCLUDED_PolySolver_H
@@ -0,0 +1,146 @@
// ======================================================================
//
// PositionVertexIndexer.cpp
// copyright 2002, Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/PositionVertexIndexer.h"
#include "sharedFoundation/Crc.h"
#include <algorithm>
#include <limits>
#include <vector>
// ======================================================================
namespace PositionVertexIndexerNamespace
{
size_t const s_bucketSize = 149;
}
using namespace PositionVertexIndexerNamespace;
// ======================================================================
PositionVertexIndexer::PositionVertexIndexer() :
m_vertices(new VectorVector),
m_indexMap(new VertexIndexMap(s_bucketSize))
{
}
// ----------------------------------------------------------------------
PositionVertexIndexer::~PositionVertexIndexer()
{
delete m_vertices;
m_vertices = 0;
delete m_indexMap;
m_indexMap = 0;
}
// ----------------------------------------------------------------------
void PositionVertexIndexer::reserve(int const numberOfVertices)
{
DEBUG_FATAL(numberOfVertices < 0, ("PositionVertexIndexer::reserve: numberOfVertices < 0"));
m_vertices->reserve(static_cast<size_t>(numberOfVertices));
}
// ----------------------------------------------------------------------
int PositionVertexIndexer::addVertex(Vector const & vertex)
{
uint32 const key = Crc::calculate(&vertex,sizeof(vertex));
std::pair<VertexIndexMap::iterator, VertexIndexMap::iterator> collisions = m_indexMap->equal_range(key);
bool insertVertex = true;
int index = 0;
if (collisions.first != m_indexMap->end())
{
// set insertVertex to false.
insertVertex = false;
// if so, look for collisions.
for (; collisions.first != collisions.second; ++collisions.first)
{
index = collisions.first->second;
Vector const & existingVertex = (*m_vertices)[static_cast<size_t>(index)];
// if we find a collision, insert the vertex instead of returning the existing index.
if (vertex != existingVertex)
{
insertVertex = true;
break;
}
}
}
if (insertVertex)
{
// add a unique vertex to the map.
// get current index.
index = static_cast<int>(m_vertices->size());
// add to list.
m_vertices->push_back(vertex);
// insert into map.
IGNORE_RETURN(m_indexMap->insert(std::make_pair(key, index)));
}
return index;
}
// ----------------------------------------------------------------------
int PositionVertexIndexer::getNumberOfVertices() const
{
return static_cast<int>(m_vertices->size());
}
// ----------------------------------------------------------------------
void PositionVertexIndexer::clear()
{
m_vertices->clear();
m_indexMap->clear();
}
// ----------------------------------------------------------------------
Vector const & PositionVertexIndexer::getVertex(int const index) const
{
VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfVertices());
return (*m_vertices)[static_cast<size_t>(index)];
}
// ----------------------------------------------------------------------
Vector & PositionVertexIndexer::getVertex(int const index)
{
VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfVertices());
return (*m_vertices)[static_cast<size_t>(index)];
}
// ----------------------------------------------------------------------
PositionVertexIndexer::VectorVector const & PositionVertexIndexer::getVertices() const
{
return *m_vertices;
}
// ----------------------------------------------------------------------
PositionVertexIndexer::VectorVector & PositionVertexIndexer::getVertices()
{
return *m_vertices;
}
// ======================================================================
@@ -0,0 +1,53 @@
// ======================================================================
//
// PositionVertexIndexer.h
// Copyright 2004, Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_PositionVertexIndexer_H
#define INCLUDED_PositionVertexIndexer_H
// ======================================================================
#include "sharedMath/Vector.h"
#include <hash_map>
// ======================================================================
class PositionVertexIndexer
{
public:
typedef stdvector<Vector>::fwd VectorVector;
PositionVertexIndexer();
~PositionVertexIndexer();
void clear();
void reserve(int numberOfVertices);
int addVertex(Vector const & vertex);
int getNumberOfVertices() const;
Vector const & getVertex(int index) const;
VectorVector const & getVertices() const;
Vector & getVertex(int index);
VectorVector & getVertices();
private:
PositionVertexIndexer(PositionVertexIndexer const &);
PositionVertexIndexer & operator=(PositionVertexIndexer const &);
private:
typedef std::hash_multimap<uint32 /*crc*/, int /*index*/> VertexIndexMap;
VectorVector * m_vertices;
VertexIndexMap * m_indexMap;
};
// ======================================================================
#endif
@@ -0,0 +1,356 @@
// ======================================================================
//
// Quaternion.cpp
// Portions Copyright 1999, Bootprint Entertainment
// Portions Copyright 2001, 2002 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Quaternion.h"
#include "sharedMath/Transform.h"
#include "sharedMath/Vector.h"
// ======================================================================
namespace QuaternionNamespace
{
float const s_quatEpsilon = 1.19209e-007f;
float const s_quatEqualityEpsilon = 1e-027f;
}
using namespace QuaternionNamespace;
// ======================================================================
const Quaternion Quaternion::identity;
// ======================================================================
Quaternion::Quaternion(void) :
w(1.0f),
x(0.0f),
y(0.0f),
z(0.0f)
{
}
// ----------------------------------------------------------------------
/**
* construct a quaternion representing the rotational orientation specified
* by the given transform.
*/
Quaternion::Quaternion(const Transform &transform) :
w(1.0f),
x(0.0f),
y(0.0f),
z(0.0f)
{
const float trace = transform.matrix[0][0] + transform.matrix[1][1] + transform.matrix[2][2] + 1.0f;
if (trace >= 2.0f)
{
const float sqrtTrace = sqrt(trace);
w = sqrtTrace * 0.5f;
const float d = 0.5f / sqrtTrace;
x = (transform.matrix[2][1] - transform.matrix[1][2]) * d;
y = (transform.matrix[0][2] - transform.matrix[2][0]) * d;
z = (transform.matrix[1][0] - transform.matrix[0][1]) * d;
}
else
{
int i = 0, j = 1, k = 2;
if (transform.matrix[1][1] > transform.matrix[i][i])
i = 1, j = 2, k = 0;
if (transform.matrix[2][2] > transform.matrix[i][i])
i = 2, j = 0, k = 1;
// super hack for efficiency
float *v = &x;
v[i] = sqrt(((transform.matrix[i][i] - transform.matrix[j][j]) - transform.matrix[k][k]) + 1.0f) * 0.5f; //lint !e662 !e661
const float d = 1.0f / (4.0f * v[i]); //lint !e662 !e661
v[j] = (transform.matrix[j][i] + transform.matrix[i][j]) * d;
v[k] = (transform.matrix[k][i] + transform.matrix[i][k]) * d; //lint !e661
w = (transform.matrix[k][j] - transform.matrix[j][k]) * d;
}
}
// ----------------------------------------------------------------------
/**
* construct a quaternion representing the orientation specified by spinning
* 'angle' number of radians around unit vector 'vector'.
*
* Make sure 'vector' is normalized. This routine will not normalize it
* for you.
*
* @param angle [IN] angle to spin around vector (in radians)
* @param vector [IN] vector around which angle is spun (must be normalized)
*/
Quaternion::Quaternion(float angle, const Vector &vector) :
w(0.0f),
x(0.0f),
y(0.0f),
z(0.0f)
{
// -TRF- do a DEBUG_FATAL check on magnitude to ensure it is nearly 1.0
const float halfAngle = 0.5f * angle;
const float sinHalfAngle = sin(halfAngle);
w = cos(halfAngle);
x = vector.x * sinHalfAngle;
y = vector.y * sinHalfAngle;
z = vector.z * sinHalfAngle;
}
// ----------------------------------------------------------------------
Quaternion::Quaternion(float newW, float newX, float newY, float newZ) :
w(newW),
x(newX),
y(newY),
z(newZ)
{
}
// ----------------------------------------------------------------------
Quaternion::~Quaternion(void)
{
}
// ----------------------------------------------------------------------
void Quaternion::getTransform(Transform *transform) const
{
NOT_NULL(transform);
getTransformPreserveTranslation(transform);
transform->setPosition_p(Vector::zero);
}
// ----------------------------------------------------------------------
void Quaternion::getTransformPreserveTranslation(Transform *transform) const
{
DEBUG_FATAL(!transform, ("null transform arg"));
if ((w + s_quatEqualityEpsilon) < 1.f)
{
const float yyTimes2 = y * y * 2.0f;
const float zzTimes2 = z * z * 2.0f;
const float xyTimes2 = x * y * 2.0f;
const float wzTimes2 = w * z * 2.0f;
const float xzTimes2 = x * z * 2.0f;
const float wyTimes2 = w * y * 2.0f;
transform->matrix[0][0] = (1.0f - yyTimes2) - zzTimes2;
transform->matrix[0][1] = xyTimes2 - wzTimes2;
transform->matrix[0][2] = xzTimes2 + wyTimes2;
const float xxTimes2 = x * x * 2.0f;
const float yzTimes2 = y * z * 2.0f;
const float wxTimes2 = w * x * 2.0f;
transform->matrix[1][0] = xyTimes2 + wzTimes2;
transform->matrix[1][1] = (1.0f - xxTimes2) - zzTimes2;
transform->matrix[1][2] = yzTimes2 - wxTimes2;
transform->matrix[2][0] = xzTimes2 - wyTimes2;
transform->matrix[2][1] = yzTimes2 + wxTimes2;
transform->matrix[2][2] = (1.0f - xxTimes2) - yyTimes2;
}
else
{
transform->resetRotate_l2p();
}
}
// ----------------------------------------------------------------------
const Quaternion Quaternion::operator -(void) const
{
return Quaternion(-w, -x, -y, -z);
}
// ----------------------------------------------------------------------
Quaternion &Quaternion::operator +=(const Quaternion &rhs)
{
w += rhs.w;
x += rhs.x;
y += rhs.y;
z += rhs.z;
return *this;
}
// ----------------------------------------------------------------------
Quaternion &Quaternion::operator -=(const Quaternion &rhs)
{
w -= rhs.w;
x -= rhs.x;
y -= rhs.y;
z -= rhs.z;
return *this;
}
// ----------------------------------------------------------------------
Quaternion &Quaternion::operator *=(const Quaternion &rhs)
{
// not effective to define this here since we'd need to save all the values
// as we computed them anyway.
*this = Quaternion(*this) * rhs;
return *this;
} //lint !e1762 // function could be const - huh? no it couldn't...
// ----------------------------------------------------------------------
float Quaternion::getMagnitudeSquared(void) const
{
return w * w + x * x + y * y + z * z;
}
// ----------------------------------------------------------------------
void Quaternion::normalize(void)
{
float reciprocalMag = 1.0f / sqrt( x * x + y * y + z * z + w * w );
x *= reciprocalMag;
y *= reciprocalMag;
z *= reciprocalMag;
w *= reciprocalMag;
}
// ----------------------------------------------------------------------
/**
* perform spherical linear interpolation between this quaternion and
* 'other' quaternion.
*
* This routine performs a spherical linear interpolation between the
* orientation represented by this quaternion and the orientation
* represented by 'other' quaternion. 'fractionOfOther' specifies
* the fraction of 'other' blended with this quaternion. A fraction
* of 0.0 indicates only this quaternion, whereas a fraction of 1.0
* indicates only the 'other' quaternion. Values in between represent
* a spherical linear interpolation between the two quaternions.
*
* Although not a strict requirement, 'fractionOfOther' typically should
* be restricted to the range zero to one.
*/
const Quaternion Quaternion::slerp(const Quaternion & otherOriginal, float fractionOfOther) const
{
// rls - check ensure interpolation using the shortest path around the "hypersphere."
float const dotOriginal = dot(otherOriginal);
Quaternion const otherClosest(dotOriginal < 0.0f ? -otherOriginal : otherOriginal);
float const cosTheta = dot(otherClosest);
if ((1.0f + cosTheta) > s_quatEpsilon)
{
float c1, c2;
// usual case. this means sin theta has enough value.
if ((1.0f - cosTheta) > s_quatEpsilon)
{
// usual
float const theta = acos(cosTheta);
float const ooSinTheta = 1.0f / sin(theta); // rls - multiply instead of divide.
float const fractionTimesTheta = fractionOfOther * theta;
c1 = sin(theta - fractionTimesTheta) * ooSinTheta;
c2 = sin(fractionTimesTheta) * ooSinTheta;
}
else
{
// ends very close
c1 = 1.0f - fractionOfOther;
c2 = fractionOfOther;
}
return Quaternion(
c1 * w + c2 * otherClosest.w,
c1 * x + c2 * otherClosest.x,
c1 * y + c2 * otherClosest.y,
c1 * z + c2 * otherClosest.z
);
}
// ends nearly opposite
float const fractionTimesTheta = PI * fractionOfOther;
float const c1 = sin(PI_OVER_2 - fractionTimesTheta);
float const c2 = sin(fractionTimesTheta);
return Quaternion(
c1 * w + c2 * z,
c1 * x - c2 * y,
c1 * y + c2 * x,
c1 * z - c2 * w
);
}
// ----------------------------------------------------------------------
const Quaternion Quaternion::operator +(const Quaternion &rhs) const
{
return Quaternion(w + rhs.w, x + rhs.x, y + rhs.y, z + rhs.z);
}
// ----------------------------------------------------------------------
const Quaternion Quaternion::operator -(const Quaternion &rhs) const
{
return Quaternion(w - rhs.w, x - rhs.x, y - rhs.y, z - rhs.z);
}
// ----------------------------------------------------------------------
const Quaternion Quaternion::operator *(const Quaternion &rhs) const
{
// rls - do not multiply by identity quaternions.
if ((rhs.w + s_quatEqualityEpsilon) >= 1.f)
{
return *this; // return *this because the other is an identity quaternion.
}
else if ((w + s_quatEqualityEpsilon) >= 1.f)
{
return rhs; // return rhs because this quaternion is an identity quaternion.
}
// Equation from CRC Concise Encyclopedia of Mathematics, p 1494, equations 24 and 25
//
// Assume quaternion of form (a1,A) = a1 + a2*i + a3*j + a4*k
// (that is, A = [a2 a3 a4]T)
// then (s1,V1) * (s2,V2) = (s1*s2 - V1 <dot> V2, s1*V2 + s2*V1 + V1 <cross> V2)
// where <dot> = dot product binary operator and
// <cross> = cross product binary operator
//
// lhs * rhs
//
// w = w * rhs.w - (x * rhs.x + y * rhs.y + z * rhs.z)
// x = w * rhs.x + rhs.w * x + (y * rhs.z - z * rhs.y)
// y = w * rhs.y + rhs.w * y + (z * rhs.x - x * rhs.z)
// z = w * rhs.z + rhs.w * z + (x * rhs.y - y * rhs.x)
return Quaternion(
w * rhs.w - (x * rhs.x + y * rhs.y + z * rhs.z),
w * rhs.x + rhs.w * x + (y * rhs.z - z * rhs.y),
w * rhs.y + rhs.w * y + (z * rhs.x - x * rhs.z),
w * rhs.z + rhs.w * z + (x * rhs.y - y * rhs.x)
);
}
// ----------------------------------------------------------------------
void Quaternion::debugDump() const
{
DEBUG_REPORT_LOG(true, ("[w=%g,x=%g,y=%g,z=%g]\n", w, x, y, z));
}
// ======================================================================
@@ -0,0 +1,108 @@
// ======================================================================
//
// Quaternion.h
// Portions Copyright 1999, Bootprint Entertainment
// Portions Copyright 2001, 2002 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_Quaternion_H
#define INCLUDED_Quaternion_H
// ======================================================================
class Transform;
class Vector;
// ======================================================================
class Quaternion
{
friend class Iff;
public:
static const Quaternion identity;
public:
real w;
real x;
real y;
real z;
public:
Quaternion(void);
explicit Quaternion(const Transform &transform);
Quaternion(real angle, const Vector &vector);
Quaternion(real newW, real newX, real newY, real newZ);
~Quaternion(void);
bool operator ==(const Quaternion &rhs);
bool operator !=(const Quaternion &rhs);
const Quaternion operator -(void) const;
Quaternion &operator +=(const Quaternion &rhs);
Quaternion &operator -=(const Quaternion &rhs);
Quaternion &operator *=(const Quaternion &rhs);
const Quaternion operator +(const Quaternion &rhs) const;
const Quaternion operator -(const Quaternion &rhs) const;
const Quaternion operator *(const Quaternion &rhs) const;
void getTransform(Transform *transform) const;
void getTransformPreserveTranslation(Transform *transform) const;
real getMagnitudeSquared(void) const;
const Quaternion slerp(const Quaternion &other, real fractionOfOther) const;
void normalize(void);
Quaternion getComplexConjugate() const;
void debugDump() const;
real dot(Quaternion const & rhs) const;
};
// ======================================================================
/**
* Retrieve the complex conjugate of this Quaternion instance.
*
* When a Quaternion has a unit length Vector, the complex conjugate
* is equivalent to the inverse. This is similar to a pure rotation
* matrix, which has a simple inverse equivalent to the transpose of
* the matrix.
*
* @return
*/
inline Quaternion Quaternion::getComplexConjugate() const
{
return Quaternion(w, -x, -y, -z);
}
// ----------------------------------------------------------------------
inline bool Quaternion::operator ==(const Quaternion &rhs)
{
return (w == rhs.w && x == rhs.x && y == rhs.y && z == rhs.z);
}
// ----------------------------------------------------------------------
inline bool Quaternion::operator !=(const Quaternion &rhs)
{
return !(*this == rhs);
}
inline real Quaternion::dot(Quaternion const & rhs) const
{
return w * rhs.w + x * rhs.x + y * rhs.y + z * rhs.z;
}
// ======================================================================
#endif
@@ -0,0 +1,98 @@
//===================================================================
//
// Rectangle2d.cpp
// asommers 7-26-99
//
// copyright 1999, bootprint entertainment
// copyright 2001, sony online entertainment
//
//===================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Rectangle2d.h"
#include "sharedMath/Line2d.h"
#include "sharedMath/Vector2d.h"
#include <algorithm>
//===================================================================
inline bool WithinRange(float rangeMin, float const value, float rangeMax)
{
if (rangeMin > rangeMax)
std::swap(rangeMin, rangeMax);
return (value >= rangeMin) && (value <= rangeMax);
}
//===================================================================
const Vector2d Rectangle2d::getCenter () const
{
Vector2d tmp;
tmp.x = x0 + getWidth () * 0.5f;
tmp.y = y0 + getHeight () * 0.5f;
return tmp;
}
//-------------------------------------------------------------------
bool Rectangle2d::isWithin (const Vector2d& point) const
{
return isWithin (point.x, point.y);
}
//-------------------------------------------------------------------
void Rectangle2d::expand (const Vector2d& point)
{
expand (point.x, point.y);
}
//-------------------------------------------------------------------
void Rectangle2d::translate (const Vector2d& point)
{
translate (point.x, point.y);
}
//-------------------------------------------------------------------
void Rectangle2d::scale (const float scalar)
{
const Vector2d center = getCenter ();
x0 = (x0 - center.x) * scalar + center.x;
y0 = (y0 - center.y) * scalar + center.y;
x1 = (x1 - center.x) * scalar + center.x;
y1 = (y1 - center.y) * scalar + center.y;
}
//-------------------------------------------------------------------
bool Rectangle2d::intersects (Line2d const & line) const
{
Vector2d intersection;
Vector2d const v0(x0, y0);
Vector2d const v1(x1, y0);
if (line.findIntersection(v0, v1, intersection) && WithinRange(v0.x, intersection.x, v1.x) && WithinRange(v0.y, intersection.y, v1.y))
return true;
Vector2d const v2(x1, y1);
if (line.findIntersection(v1, v2, intersection) && WithinRange(v1.x, intersection.x, v2.x) && WithinRange(v1.y, intersection.y, v2.y))
return true;
Vector2d const v3(x0, y1);
if (line.findIntersection(v2, v3, intersection) && WithinRange(v2.x, intersection.x, v3.x) && WithinRange(v2.y, intersection.y, v3.y))
return true;
if (line.findIntersection(v3, v0, intersection) && WithinRange(v3.x, intersection.x, v0.x) && WithinRange(v3.y, intersection.y, v0.y))
return true;
return false;
}
//===================================================================
@@ -0,0 +1,208 @@
//
// Rectangle2d.h
// asommers 7-26-99
//
// copyright 1999, bootprint entertainment
// copyright 2001, sony online entertainment
//
//-------------------------------------------------------------------
#ifndef INCLUDED_Rectangle2d_H
#define INCLUDED_Rectangle2d_H
//-------------------------------------------------------------------
class Line2d;
class Vector2d;
//-------------------------------------------------------------------
class Rectangle2d
{
public:
//-- lower left
float x0;
float y0;
//-- upper right
float x1;
float y1;
public:
Rectangle2d ();
Rectangle2d (float newX0, float newY0, float newX1, float newY1);
~Rectangle2d ();
void set (float newX0, float newY0, float newX1, float newY1);
float getWidth () const;
float getHeight () const;
const Vector2d getCenter () const;
bool isWithin (float x, float y) const;
bool isWithin (const Vector2d& point) const;
bool isVector2d () const;
void expand (float x, float y);
void expand (const Vector2d& point);
void expand (const Rectangle2d& rectangle);
void translate (float x, float y);
void translate (const Vector2d& point);
void scale (float scalar);
bool intersects (const Rectangle2d& other) const;
bool contains (Rectangle2d const & other) const;
bool intersects (Line2d const & line) const;
bool operator== (const Rectangle2d& rhs) const;
bool operator!= (const Rectangle2d& rhs) const;
};
//-------------------------------------------------------------------
inline Rectangle2d::Rectangle2d () :
x0 (0),
y0 (0),
x1 (0),
y1 (0)
{
}
//-------------------------------------------------------------------
inline Rectangle2d::Rectangle2d (const float newX0, const float newY0, const float newX1, const float newY1) :
x0 (newX0),
y0 (newY0),
x1 (newX1),
y1 (newY1)
{
}
//-------------------------------------------------------------------
inline Rectangle2d::~Rectangle2d ()
{
}
//-------------------------------------------------------------------
inline void Rectangle2d::set (const float newX0, const float newY0, const float newX1, const float newY1)
{
x0 = newX0;
y0 = newY0;
x1 = newX1;
y1 = newY1;
}
//-------------------------------------------------------------------
inline float Rectangle2d::getWidth () const
{
return abs(x1 - x0);
}
//-------------------------------------------------------------------
inline float Rectangle2d::getHeight () const
{
return abs(y1 - y0);
}
//-------------------------------------------------------------------
inline bool Rectangle2d::isWithin (const float x, const float y) const
{
if (x0 < x1)
if (y0 < y1)
return
WithinRangeInclusiveInclusive (x0, x, x1) &&
WithinRangeInclusiveInclusive (y0, y, y1);
else
return
WithinRangeInclusiveInclusive (x0, x, x1) &&
WithinRangeInclusiveInclusive (y1, y, y0);
else
if (y0 < y1)
return
WithinRangeInclusiveInclusive (x1, x, x0) &&
WithinRangeInclusiveInclusive (y0, y, y1);
else
return
WithinRangeInclusiveInclusive (x1, x, x0) &&
WithinRangeInclusiveInclusive (y1, y, y0);
}
//-------------------------------------------------------------------
inline bool Rectangle2d::isVector2d () const
{
return x0 == x1 && y0 == y1;
}
//-------------------------------------------------------------------
inline void Rectangle2d::expand (const float x, const float y)
{
if (x < x0)
x0 = x;
if (y < y0)
y0 = y;
if (x > x1)
x1 = x;
if (y > y1)
y1 = y;
}
//-------------------------------------------------------------------
inline void Rectangle2d::expand (const Rectangle2d& rectangle)
{
expand (rectangle.x0, rectangle.y0);
expand (rectangle.x1, rectangle.y0);
expand (rectangle.x0, rectangle.y1);
expand (rectangle.x1, rectangle.y1);
}
//-------------------------------------------------------------------
inline void Rectangle2d::translate (const float x, const float y)
{
x0 += x;
y0 += y;
x1 += x;
y1 += y;
}
//-------------------------------------------------------------------
inline bool Rectangle2d::intersects (const Rectangle2d& other) const
{
return !(x1 < other.x0 || x0 > other.x1 || y1 < other.y0 || y0 > other.y1);
}
//-------------------------------------------------------------------
inline bool Rectangle2d::contains (Rectangle2d const & other) const
{
return other.x0 >= x0 && other.x1 <= x1 && other.y0 >= y0 && other.y1 <= y1;
}
//-------------------------------------------------------------------
inline bool Rectangle2d::operator== (const Rectangle2d& rhs) const
{
return x0 == rhs.x0 && x1 == rhs.x1 && y0 == rhs.y0 && y1 == rhs.y1;
}
//-------------------------------------------------------------------
inline bool Rectangle2d::operator!= (const Rectangle2d& rhs) const
{
return !operator== (rhs);
}
//-------------------------------------------------------------------
#endif
@@ -0,0 +1,36 @@
// ======================================================================
//
// SetupSharedMath.cpp
// Copyright 2002 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/SetupSharedMath.h"
#include "sharedMath/ConfigSharedMath.h"
#include "sharedMath/CompressedQuaternion.h"
#include "sharedMath/PaletteArgb.h"
#include "sharedMath/PaletteArgbList.h"
#include "sharedMath/Transform.h"
#include "sharedDebug/InstallTimer.h"
// ======================================================================
void SetupSharedMath::install()
{
InstallTimer const installTimer("SetupSharedMath::install");
ConfigSharedMath::install();
//-- install palette support
PaletteArgb::install();
PaletteArgbList::install();
// @todo don't bother installing this on the servers; it's unnecessary.
CompressedQuaternion::install();
Transform::install();
}
// ======================================================================
@@ -0,0 +1,24 @@
// ======================================================================
//
// SetupSharedMath.h
// Copyright 2002 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_SetupSharedMath_H
#define INCLUDED_SetupSharedMath_H
// ======================================================================
class SetupSharedMath
{
public:
static void install();
};
// ======================================================================
#endif
@@ -0,0 +1,41 @@
// SpatialSubdivision.cpp
// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved.
// Author: Justin Randall
//-----------------------------------------------------------------------
#pragma warning ( disable : 4514 ) // unreferenced inline function has been removed
#include "sharedMath/FirstSharedMath.h"
#include "SpatialSubdivision.h"
//-----------------------------------------------------------------------
SpatialSubdivisionHandle::SpatialSubdivisionHandle()
{
}
//-----------------------------------------------------------------------
SpatialSubdivisionHandle::SpatialSubdivisionHandle(const SpatialSubdivisionHandle &)
{
}
//-----------------------------------------------------------------------
SpatialSubdivisionHandle::~SpatialSubdivisionHandle()
{
}
//-----------------------------------------------------------------------
SpatialSubdivisionHandle & SpatialSubdivisionHandle::operator = (const SpatialSubdivisionHandle & rhs)
{
if(this != &rhs)
{
// make assignments if right hand side is not this instance
}
return *this;
}
//-----------------------------------------------------------------------
@@ -0,0 +1,124 @@
// SpatialSubdivision.h
// copyright 2001 Sony Online Entertainment
// Author: Justin Randall
#ifndef _INCLUDED_SpatialSubdivision_H
#define _INCLUDED_SpatialSubdivision_H
//-----------------------------------------------------------------------
class Vector;
//-----------------------------------------------------------------------
/**
Helper handle to expedite operations in a particular spatial
subdivision implementation (e.g. moving an object within a Sphere or
overlapped quadrant, traversing up from a leaf in a tree structure,
etc..)
*/
class SpatialSubdivisionHandle
{
public:
SpatialSubdivisionHandle();
virtual ~SpatialSubdivisionHandle() = 0;
SpatialSubdivisionHandle(const SpatialSubdivisionHandle & source);
SpatialSubdivisionHandle & operator=(const SpatialSubdivisionHandle & source);
};
//-----------------------------------------------------------------------
/**
@brief a templatized base class for a spatially organized container.
The SpatialSubdivision template defines an interface for all
spatially organized containers. Specific implementations may
be partially templatized (specifying the extent type, for example)
while leaving other implementation details, such as ObjectType
and ExtentAccessor routines configurable per instantiation.
For example, a multiplayer game application may have ClientObject
types on the game client, which organizes data in a Quadtree, using
axis aligned bounding boxes for extent information. A game server may
have a ServerObject that defines its extent as a Sphere and
organizes objects in a SphereTree. Additionally, a game message
routing server may have ClientConnection objects that use
Sphere extents. A single SphereTree implementation derived
from the SpatialSubdivision template could be declared as:
\code
template<class ObjectType, class ExtentAccessor>
class SphereTree : public SpatialSubdivision<ObjectType, Sphere, ExtentAccessor>
\endcode
or the client Quadtree as
\code
class QuadTree : public SpatialSubdivision<ClientObject, AxisAlignedBoundingBox, ClientObject>
\endcode
There is little penalty for generalization, since the implementation
may be written very specifically for a particular application, yet
maintain a common template interface that does not rely on objects or
extents.
Because the SpatialSubdivision class is intended to be an interface
definition, it doesn't DO anything and is pure virtual.
@author Justin Randall
*/
template <class ObjectType>
class SpatialSubdivisionFilter
{
public:
virtual ~SpatialSubdivisionFilter() {}
virtual bool operator()(const ObjectType &) const=0;
};
template<class ObjectType, class ExtentType, class ExtentAccessor>
class SpatialSubdivision
{
public:
SpatialSubdivision ();
virtual ~SpatialSubdivision () = 0;
virtual SpatialSubdivisionHandle * addObject (ObjectType object) = 0;
virtual const bool canSee (SpatialSubdivisionHandle * target, const Vector & start, const float distance, const float fov=0.0f) const = 0; //lint !e1735 // virtual function has default parameter
virtual void findInRange (const Vector & origin, const float distance, typename stdvector<ObjectType>::fwd & results) const = 0;
virtual void findInRange (const Vector & origin, const float distance, const SpatialSubdivisionFilter<ObjectType> &filter, typename stdvector<ObjectType>::fwd & results) const = 0;
virtual void findOnRay (const Vector & begin, const Vector & dir, typename stdvector<ObjectType>::fwd & results) const = 0;
virtual void findOnSegment (const Vector & begin, const Vector & end, typename stdvector<ObjectType>::fwd & results) const = 0;
virtual void move (SpatialSubdivisionHandle * object) = 0;
virtual void removeObject (SpatialSubdivisionHandle * object) = 0;
private:
SpatialSubdivision & operator = (const SpatialSubdivision & rhs);
SpatialSubdivision(const SpatialSubdivision & source);
};
//-----------------------------------------------------------------------
/**
@brief construct for a SpatialSubdivision template instance.
This constructor doesn't do anything. It is present for completeness.
@author Justin Randall
*/
template<class ObjectType, class ExtentType, class ExtentAccessor>
inline SpatialSubdivision<ObjectType, ExtentType, ExtentAccessor>::SpatialSubdivision()
{
}
//-----------------------------------------------------------------------
/**
@brief destroy a SpatialSubdivision template instance
This destructor doesn't do anything. It is present for completeness.
@author Justin Randall
*/
template<class ObjectType, class ExtentType, class ExtentAccessor>
inline SpatialSubdivision<ObjectType, ExtentType, ExtentAccessor>::~SpatialSubdivision()
{
}
//-----------------------------------------------------------------------
#endif // _INCLUDED_SpatialSubdivision_H
@@ -0,0 +1,113 @@
// ======================================================================
//
// Sphere.cpp
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#include "sharedMath/FirstSharedMath.h"
#include "sharedMath/Sphere.h"
#include "sharedMath/Range.h"
#include "sharedMath/Circle.h"
// ======================================================================
/// Sphere centered at (0,0,0) with a radius of 0.
const Sphere Sphere::zero;
/// Sphere centered at (0,0,0) with a radius of 1.
const Sphere Sphere::unit(Vector::zero, CONST_REAL(1));
// ======================================================================
Circle Sphere::getCircle ( void ) const
{
return Circle(m_center,m_radius);
}
Range Sphere::getRangeX ( void ) const
{
return Range( m_center.x - m_radius, m_center.x + m_radius );
}
Range Sphere::getRangeY ( void ) const
{
return Range( m_center.y - m_radius, m_center.y + m_radius );
}
Range Sphere::getRangeZ ( void ) const
{
return Range( m_center.z - m_radius, m_center.z + m_radius );
}
bool Sphere::intersectsCone(Vector const & coneBase, Vector const & coneNormal, float const coneAngleRadians) const
{
float const angleSine = sinf(coneAngleRadians);
float const angleCosine = cosf(coneAngleRadians);
float const angleInverseSine = angleSine > FLT_MIN ? 1.0f / angleSine : 0.0f;
float const angleCosineSquared = sqr(angleCosine);
Vector const & vectorToSphere = m_center - coneBase;
Vector const & intersectPosition = vectorToSphere + (m_radius * angleInverseSine) * coneNormal;
float magnitudeOfIntersectionSquared = intersectPosition.magnitudeSquared();
float angleBetweenSourceAndIntersection = intersectPosition.dot(coneNormal);
bool inCone = false;
if (angleBetweenSourceAndIntersection > FLT_MIN && sqr(angleBetweenSourceAndIntersection) >= magnitudeOfIntersectionSquared * angleCosineSquared)
{
float const angleSinSquared = sqr(angleSine);
magnitudeOfIntersectionSquared = vectorToSphere.magnitudeSquared();
angleBetweenSourceAndIntersection = -vectorToSphere.dot(coneNormal);
if (angleBetweenSourceAndIntersection > FLT_MIN && sqr(angleBetweenSourceAndIntersection) >= magnitudeOfIntersectionSquared * angleSinSquared)
{
float const rangeSquared = sqr(m_radius);
inCone = magnitudeOfIntersectionSquared <= rangeSquared;
}
else
{
inCone = true;
}
}
return inCone;
}
Vector Sphere::closestPointOnSphere(Vector const & point) const
{
Vector pointOnSurface;
Vector normalToPoint(point - m_center);
if(normalToPoint.normalize())
{
pointOnSurface = m_center + (normalToPoint * m_radius);
}
else
{
pointOnSurface = m_center;
}
return pointOnSurface;
}
Vector Sphere::approximateClosestPointOnSphere(Vector const & point) const
{
Vector pointOnSurface;
Vector normalToPoint(point - m_center);
if(normalToPoint.approximateNormalize())
{
pointOnSurface = m_center + (normalToPoint * m_radius);
}
else
{
pointOnSurface = m_center;
}
return pointOnSurface;
}
// ======================================================================
@@ -0,0 +1,347 @@
// ======================================================================
//
// Sphere.h
// copyright (c) 2001 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_Sphere_H
#define INCLUDED_Sphere_H
// ======================================================================
#include "sharedMath/Vector.h"
class Range;
class Circle;
// ======================================================================
/// Describes a sphere in 3d space.
class Sphere
{
public:
static const Sphere zero;
static const Sphere unit;
public:
// default destructor, copy constructor, assignment operator are all okay
Sphere();
Sphere(const Vector &center, real radius);
Sphere(real x, real y, real z, real radius);
void setCenter(real x, real y, real z);
void setCenter(const Vector &center);
void setRadius(real radius);
void set(const Vector &center, float radius);
void set(float x, float y, float z, float radius);
const Vector &getCenter() const;
const real getRadius() const;
Vector const & getAxisX ( void ) const;
Vector const & getAxisY ( void ) const;
Vector const & getAxisZ ( void ) const;
float getExtentX ( void ) const;
float getExtentY ( void ) const;
float getExtentZ ( void ) const;
Circle getCircle ( void ) const;
bool contains(const Vector &point) const;
bool contains(const Sphere &other) const;
bool intersectsLine(const Vector &startPoint, const Vector &endPoint) const;
bool intersectsLineSegment(const Vector &startPoint, const Vector &endPoint) const;
bool intersectsRay(const Vector & startPoint, const Vector & normalizedDirection) const;
bool intersectsSphere(const Sphere &other) const;
bool intersectsCone(Vector const & coneBase, Vector const & coneNormal, float coneAngleRadians) const;
Vector closestPointOnSphere(Vector const & point) const;
Vector approximateClosestPointOnSphere(Vector const & point) const;
bool operator==(const Sphere & rhs) const;
Range getRangeX ( void ) const;
Range getRangeY ( void ) const;
Range getRangeZ ( void ) const;
private:
/// Center point of the sphere.
Vector m_center;
/// Radius of the sphere.
real m_radius;
};
// ======================================================================
/**
* Construct a default sphere.
*
* The sphere will be centered at (0,0,0) and have a radius of 0.
*/
inline Sphere::Sphere()
:
m_center(),
m_radius(0)
{
}
// ----------------------------------------------------------------------
/**
* Construct a sphere.
*
* @param center The center point for the sphere.
* @param radius The radius of the sphere.
*/
inline Sphere::Sphere(const Vector &center, real radius)
:
m_center(center),
m_radius(radius)
{
WARNING_STRICT_FATAL(m_radius < 0.0f, ("Sphere has negative radius!"));
if(m_radius < 0.0f)
radius = 0.0f;
}
// ----------------------------------------------------------------------
/**
* Construct a sphere
*
* @param x The X center point of the sphere.
* @param y The Y center point of the sphere.
* @param z The Z center point of the sphere.
* @param radius The radius of the sphere.
*/
inline Sphere::Sphere(real x, real y, real z, real radius)
:
m_center(Vector(x, y, z)),
m_radius(radius)
{
WARNING_STRICT_FATAL(m_radius < 0.0f, ("Sphere has negative radius!"));
if(m_radius < 0.0f)
radius = 0.0f;
}
// ----------------------------------------------------------------------
/**
* Set the center point of the sphere.
*
* @param x The new X center point of the sphere.
* @param y The new Y center point of the sphere.
* @param z The new Z center point of the sphere.
*/
inline void Sphere::setCenter(const real x, const real y, const real z)
{
m_center.x = x;
m_center.y = y;
m_center.z = z;
}
// ----------------------------------------------------------------------
/**
* Set the center point of the sphere.
*
* @param center The new center point of the sphere.
*/
inline void Sphere::setCenter(const Vector &center)
{
m_center = center;
}
// ----------------------------------------------------------------------
/**
* Set the radius of the sphere.
*
* @param radius The new radius of the sphere.
*/
inline void Sphere::setRadius(real radius)
{
m_radius = radius;
}
// ----------------------------------------------------------------------
inline void Sphere::set(const Vector &center, const float radius)
{
m_center = center;
m_radius = radius;
}
// ----------------------------------------------------------------------
inline void Sphere::set(const float x, const float y, const float z, const float radius)
{
m_center.x = x;
m_center.y = y;
m_center.z = z;
m_radius = radius;
}
// ----------------------------------------------------------------------
/**
* Get the center point of the sphere.
*
* @return The center point of the sphere.
*/
inline const Vector &Sphere::getCenter() const
{
return m_center;
}
// ----------------------------------------------------------------------
/**
* Get the radius of the sphere.
*
* @return The radius of the sphere.
*/
inline const real Sphere::getRadius() const
{
return m_radius;
}
// ----------------------------------------------------------------------
inline Vector const & Sphere::getAxisX ( void ) const
{
return Vector::unitX;
}
inline Vector const & Sphere::getAxisY ( void ) const
{
return Vector::unitY;
}
inline Vector const & Sphere::getAxisZ ( void ) const
{
return Vector::unitZ;
}
// ----------
inline float Sphere::getExtentX ( void ) const
{
return getRadius();
}
inline float Sphere::getExtentY ( void ) const
{
return getRadius();
}
inline float Sphere::getExtentZ ( void ) const
{
return getRadius();
}
// ----------------------------------------------------------------------
/**
* Check if a point is inside the sphere
*
* @return True if the point is in the sphere, otherwise false.
*/
inline bool Sphere::contains(const Vector &point) const
{
return m_center.magnitudeBetweenSquared(point) <= sqr(m_radius);
}
// ----------------------------------------------------------------------
/**
* Check if the sphere entirely contains another sphere.
*
* @return True if the second sphere is entirely contained within the first.
*/
inline bool Sphere::contains(const Sphere &other) const
{
if (other.m_radius <= m_radius)
{
return m_center.magnitudeBetweenSquared(other.m_center) <= sqr(m_radius - other.m_radius);
}
else
return false;
}
//-----------------------------------------------------------------------
inline bool Sphere::intersectsLine(const Vector & line0, const Vector & line1) const
{
return contains(m_center.findClosestPointOnLine(line0, line1));
}
//-----------------------------------------------------------------------
inline bool Sphere::intersectsLineSegment(const Vector & startPoint, const Vector & endPoint) const
{
return contains(m_center.findClosestPointOnLineSegment(startPoint, endPoint));
}
//-----------------------------------------------------------------------
/**
@brief determine if a ray intersects a sphere
*/
inline bool Sphere::intersectsRay(const Vector & startPoint, const Vector & normalizedDirection) const
{
// If the ray starts inside the sphere,
// it MUST intersect the sphere
if(contains(startPoint))
return true;
// get the squre magnitude between the origin of the sphere
// and the start point of the ray
Vector rayStartPointToCenter = m_center - startPoint;
// project the ling segment described by the ray start point to the
// sphere origin on the ray
const float originRayDot = rayStartPointToCenter.dot(normalizedDirection);
if(originRayDot < 0.0f)
{
// Center of the sphere is 'behind' the ray, the sphere can't intersect the ray
// without containing the start point, but since it doesn't the sphere doesn't intersect
// the ray.
return false;
}
// distanceSquared - sqr(originRayDot) = squre length of the line
// segment from the sphere origin that is perpendicular to the ray.
// If that length is less than the radius, there is an intersection.
const float distanceSquared = rayStartPointToCenter.magnitudeSquared();
const float distanceToRaySquared = sqr(m_radius) - (distanceSquared - sqr(originRayDot));
return (distanceToRaySquared > 0.0f);
}
//-----------------------------------------------------------------------
inline bool Sphere::intersectsSphere(const Sphere & other) const
{
const real d = m_center.magnitudeBetweenSquared(other.getCenter());
const real r = sqr(m_radius + other.getRadius());
return d < r;
}
//----------------------------------------------------------------------
inline bool Sphere::operator==(const Sphere & rhs) const
{
return this == &rhs || (m_radius == rhs.m_radius && m_center == rhs.m_center);
}
// ======================================================================
#endif
@@ -0,0 +1,657 @@
// SphereTree.h
// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved.
// Author: Justin Randall
#ifndef _INCLUDED_SphereTree_H
#define _INCLUDED_SphereTree_H
//-----------------------------------------------------------------------
#include "sharedMath/Sphere.h"
#include "sharedMath/Capsule.h"
#include "sharedMath/SpatialSubdivision.h"
#include "sharedMath/SphereTreeNode.h"
//-----------------------------------------------------------------------
/**
@brief a templatized implementation of a sphere tree.
A SphereTree organizes data hierarchically in sphere nodes.
Sphere nodes have a containment relationship, starting from the
more general, larger sphere nodes, to smaller, more granular
nodes which contain objects. Any node may contain objects as well
as child nodes.
The tree balances itself as it discovers usable world space.
Its depth is defined by the potential worldspace covered by the tree
and the extent data of the objects contained within the tree.
The default behavior of the tree is to provide general coverage of
world space with about 32 nodes. Child nodes follow this heuristic
as items are inserted into the tree. Item extents (by default)
want to be ten times smaller than a container node's maximum extent.
If this ratio is exceeded, the object continues to fall through the
tree until a suitable leaf node is located.
These heuristics may be tweaked, but generally show good behavior,
favoring move, range, and reintegration to insertion performance.
In simulations with 1 million objects in a 16 cubic kilometer world
space, the tree provides performance of over 1,000 move operations
per millisecond.
How it works ---
INSERTING
When an object is first added to the SphereTree, it is passed to
the root node, which encompasses all world space. If the object
falls outside of the root node, the root node is expanded, and
new max sizes for child nodes are calculated to keep the tree
generally balanced for future operations. If the object extent
exceeds the ratio of object-to-leaf-max size, then the maximum
node size is again recalculated for general balancing. The first
few insertions into the tree will trigger these recalculations,
but have no effect on existing nodes.
Once the balancing calculations are done (if they were needed at
all in the first place), the root node finds a candidate child
node to accept the new object. If no candidate exists, a new
child sphere is created, and the object is passed to the child.
The child will repeat the previous step, finding candidates
(new nodes don't check, they don't have children), and passing
the object further down the tree until a suitably sized child
node contains the object.
The default behavior is to find child nodes that are a
factor of 4 times smaller with each step towards the solution
leaf node. The solution leaf must be (by default) 10 times larger
than objects it contains.
An object with a 1 meter sphere in a 16 kilometer world follows
this path: [ root -> 4k child -> 1k child -> 250 meter child ->
62 meter child ] or a depth of 4.
MOVING
When an object moves, the destination sphere is checked against
the containing node. If the real size of the containing node's
sphere can contain the object, the operation is complete.
If the real node size cannot contain the object, then a check
is made to see if the max size can contain the object. If it
can, the node is resized and the operation completes.
If the max sphere size cannot contain the object, then the
object is passed to the parent. If the object can be contained within
the parent, then a candidate target node is identified and the
object is then placed in it.
In most cases, the object stays within the real sphere size. The
next most common case is the object being contained in the container
node's max sphere. Both of these are very fast operations and
incur little cost on the system. Re-integration is slightly more
expensive but also not as common.
The worst case is that all objects warp around and must be
fully re-integrated from the root node. This is as expensive
as insertion plus the time required to traverse up the tree
and check containment candidates en route to the root node.
The worst case simulation with 1 million objects clocked move
operations at < 0.05 milliseconds (all 1 million objects moving to
origin from random locations)
FINDING IN RANGE
When the SphereTree receives a find request, it queries the root
node for all child spheres which intersect the sphere described
by the range query (location, radius). A recursive query is
made into child nodes which satisfy the intersection query,
culling more candidates as the find operations solves for all objects
intersecting the range sphere.
Find operations are faster for smaller range spheres, slower for
larger spheres, averaging thousands of results per millisecond. Most
of the time is spent filling a result vector.
OTHER NOTES
The sphere tree defines a node handle that derives from
SpatialSubdivisionHandle. Since the superclass API defines
operations in terms of a SpatialSubdivisionHandle, the sphere
tree can use this handle to go directly to a leaf node for
move operations. The application using the SphereTree merely
needs to perform all operations (except addObject) in terms
of the handle.
Tests were performed on a 700MHz P-III system with 256MB RAM running
Windows 2000. The dev environment is MSVC.
SphereTree's are succesfully in use on Linux, gcc-2.95-3 on a RedHat 6.2,
7.0 and 7.1 distributions.
DEPENDENCIES
Sphere that defines the following:
\code
void setCenter(real x, real y, real z);
void setCenter(const Vector &center);
void setRadius(real radius);
const Vector &getCenter() const;
const real getRadius() const;
bool contains(const Vector &point) const;
bool contains(const Sphere &other) const;
bool intersectsSphere(const Sphere &other) const;
bool intersectsLine(const Vector &startPoint, const Vector &endPoint) const;
bool intersectsLineSegment(const Vector &startPoint, const Vector &endPoint) const;
bool intersectsRay(const Vector & startPoint, const Vector & normalizedDirection) const;
\endcode
and Vector that defines
\code
real magnitudeSquared(void) const;
real magnitude(void) const;
real magnitudeBetween(const Vector &vector) const;
real magnitudeBetweenSquared(const Vector &vector) const;
const Vector findClosestPointOnLine(const Vector &line0, const Vector &line1) const;
const Vector findClosestPointOnLineSegment(const Vector & startPoint, const Vector & endPoint) const;
real dot(const Vector &vector) const;
\endcode
These dependencies can be satisfied with the BootPrint/Sony Online Entertainment
sharedMath library.
@see SpatialSubdivision
@see SpatialSubdivisionHandle
@author Justin Randall
*/
template<class ObjectType, class ExtentAccessor>
class SphereTree : public SpatialSubdivision<ObjectType, Sphere, ExtentAccessor>
{
public:
typedef SphereTreeNode<ObjectType, ExtentAccessor> NodeType;
SphereTree ();
~SphereTree ();
virtual SpatialSubdivisionHandle * addObject (ObjectType object);
virtual const bool canSee (SpatialSubdivisionHandle * target, const Vector & start, const float distance, const float fov=0.0f) const;
void dumpSphereTreeObjects(std::vector<ObjectType> & results) const;
void dumpSphereTree (std::vector<std::pair<ObjectType, Sphere> > & results) const;
void dumpSphereTreeNodes(std::vector<std::pair<ObjectType, Sphere> > & results) const;
void dumpSphereTreeObjs (std::vector<std::pair<ObjectType, Sphere> > & results) const;
void dumpEdgeList (std::vector<Vector> & results) const;
virtual void findInRange (const Vector & origin, const float distance, std::vector<ObjectType> & results) const;
virtual void findInRange (const Vector & origin, const float distance, std::vector<ObjectType> & results, int & testCounter) const;
virtual void findInRange (const Vector & origin, const float distance, const SpatialSubdivisionFilter<ObjectType> &filter, std::vector<ObjectType> & results) const;
virtual void findInRange (const Vector & origin, const float distance, const SpatialSubdivisionFilter<ObjectType> &filter, std::vector<ObjectType> & results, int & testCounter) const;
virtual void findOnRay (const Vector & begin, const Vector & dir, std::vector<ObjectType> & results) const;
virtual void findOnSegment (const Vector & begin, const Vector & end, std::vector<ObjectType> & results) const;
virtual void findOnSegment(Vector const & begin, Vector const & end, SpatialSubdivisionFilter<ObjectType> const & filter, std::vector<ObjectType> & results) const;
virtual void findAtPoint (const Vector & point, std::vector<ObjectType> & results) const;
virtual void findInRange (const Capsule & range, std::vector<ObjectType> & results) const;
virtual void findInRange (const Capsule & range, const SpatialSubdivisionFilter<ObjectType> &filter, std::vector<ObjectType> & results) const;
virtual bool findClosest (const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance) const;
virtual bool findClosest (const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance, int & testCounter) const;
virtual bool findClosest2d (const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance) const;
virtual bool findClosest2d (const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance, int & testCounter) const;
virtual void move (SpatialSubdivisionHandle * object);
virtual void removeObject (SpatialSubdivisionHandle * object);
virtual void validate () const;
virtual int getNodeCount () const;
bool empty () const;
virtual int getObjectCount () const;
void apply (typename SphereTreeNode<ObjectType,ExtentAccessor>::NodeFunctor N);
bool isWithin (Vector const & position) const;
Sphere const & getRealSphere () const;
private:
SphereTree & operator = (const SphereTree & rhs);
SphereTree (const SphereTree & source);
private:
NodeType root;
};
//-----------------------------------------------------------------------
/**
@brief construct a sphere tree
Initializes the root node with no parent.
ExtentAccessor is defined in terms of a struct with a
getExtent(ObjectType) member function that returns a Sphere.
*/
template<class ObjectType, class ExtentAccessor>
inline SphereTree<ObjectType, ExtentAccessor>::SphereTree() :
root()
{
}
//-----------------------------------------------------------------------
/**
@brief destroy the sphere tree
Doesn't do anything. Included here for completeness.
*/
template<class ObjectType, class ExtentAccessor>
inline SphereTree<ObjectType, ExtentAccessor>::~SphereTree()
{
}
//-----------------------------------------------------------------------
/**
@brief add an object to the sphere tree
Calls addObject on the root node.
@see SphereTreeNode
@see SpatialSubdivision::addObject(ObjectType object)
@author Justin Randall
*/
template<class ObjectType, class ExtentAccessor>
inline SpatialSubdivisionHandle * SphereTree<ObjectType, ExtentAccessor>::addObject(ObjectType object)
{
return root.addObject(object);
}
//-----------------------------------------------------------------------
/**
@brief not implemented
@todo implement!
*/
template<class ObjectType, class ExtentAccessor>
inline const bool SphereTree<ObjectType, ExtentAccessor>::canSee(SpatialSubdivisionHandle * target, const Vector & start, const float distance, const float fov) const
{
UNREF(target);
UNREF(start);
UNREF(distance);
UNREF(fov);
//@todo implement
return true;
}
//-----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::dumpSphereTreeObjects(std::vector<ObjectType> & results) const
{
root.dumpSphereTreeObjects(results);
}
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::dumpSphereTree(std::vector<std::pair<ObjectType, Sphere> > & results) const
{
root.dumpSphereTree(results);
}
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::dumpSphereTreeNodes(std::vector<std::pair<ObjectType, Sphere> > & results) const
{
root.dumpSphereTreeNodes(results);
}
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::dumpSphereTreeObjs(std::vector<std::pair<ObjectType, Sphere> > & results) const
{
root.dumpSphereTreeObjs(results);
}
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::dumpEdgeList(std::vector<Vector>& results) const
{
root.dumpEdgeList(results);
}
//-----------------------------------------------------------------------
/**
@brief find all objects contained in a sphere defined by the range params
Finds all objects intersecting the sphere described by the origin and
distance parameters. The results are placed in the results vector.
@param origin A point describing the center of the range query
@param distance The radius of the query. The origin and distance
are used to create a Sphere at 'origin' with radius
'distance'
@param results A user supplied vector of ObjectType that will receive
the solution to the range query.
@see SpatialSubdivision::findInRange()
@see SphereTreeNode::findInRange()
@author Justin Randall
*/
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::findInRange(const Vector & origin, const float distance, std::vector<ObjectType> & results) const
{
const Sphere range(origin, distance);
root.findInRange(range, results);
}
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::findInRange(const Vector & origin, const float distance, std::vector<ObjectType> & results, int & testCounter) const
{
const Sphere range(origin, distance);
root.findInRange(range, results, testCounter);
}
//-----------------------------------------------------------------------
/**
@brief find all objects contained in a sphere defined by the range params
which meet a filter criteria
Finds all objects intersecting the sphere described by the origin and
distance parameters. The results are placed in the results vector.
@param origin A point describing the center of the range query
@param distance The radius of the query. The origin and distance
are used to create a Sphere at 'origin' with radius
'distance'
@param filter A user supplied filter functor.
filter.operator(const ObjectType & object) should return
true if the object is to be returned.
@param results A user supplied vector of ObjectType that will receive
the solution to the range query.
@see SpatialSubdivision::findInRange()
@see SphereTreeNode::findInRange()
@author Acy Stapp
*/
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::findInRange(const Vector & origin, const float distance, const SpatialSubdivisionFilter<ObjectType> &filter, std::vector<ObjectType> & results) const
{
const Sphere range(origin, distance);
root.findInRange(range, filter, results);
}
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::findInRange(const Vector & origin, const float distance, const SpatialSubdivisionFilter<ObjectType> &filter, std::vector<ObjectType> & results, int & testCounter) const
{
const Sphere range(origin, distance);
root.findInRange(range, filter, results, testCounter);
}
//-----------------------------------------------------------------------
/**
@brief find all objects that hit the given ray
Finds all objects intersecting the ray described by the start point
and direction parameters. The results are placed in the results vector.
@param begin A point describing the origin of the ray query
@param dir A vector describing the direction of the ray
@param results A user supplied vector of ObjectType that will receive the results of the query.
@see SpatialSubdivision::findOnRay()
@see SphereTreeNode::findOnRay()
@author Austin Appleby
*/
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::findOnRay(const Vector & begin, const Vector & dir, std::vector<ObjectType> & results) const
{
Vector normDir = dir;
IGNORE_RETURN( normDir.normalize() );
root.findOnRay(begin, normDir, results);
}
//-----------------------------------------------------------------------
/**
@brief find all objects that hit the given segment
Finds all objects intersecting the segment described by the start point
and end point parameters. The results are placed in the results vector.
@param begin The start point of the test segment
@param dir The end point of the test segment
@param results A user supplied vector of ObjectType that will receive the results of the query.
@see SpatialSubdivision::findOnSegment()
@see SphereTreeNode::findOnSegment()
@author Austin Appleby
*/
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::findOnSegment(const Vector & begin, const Vector & end, std::vector<ObjectType> & results) const
{
root.findOnSegment(begin, end, results);
}
//-----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::findOnSegment(Vector const & begin, Vector const & end, SpatialSubdivisionFilter<ObjectType> const & filter, std::vector<ObjectType> & results) const
{
root.findOnSegment(begin, end, filter, results);
}
//-----------------------------------------------------------------------
/**
@brief find all objects that hit the given segment
Finds all objects overlapping the given point.
The results are placed in the results vector.
@param begin The start point of the test segment
@param dir The end point of the test segment
@param results A user supplied vector of ObjectType that will receive the results of the query.
@see SpatialSubdivision::findOnSegment()
@see SphereTreeNode::findOnSegment()
@author Austin Appleby
*/
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::findAtPoint(const Vector & point, std::vector<ObjectType> & results) const
{
root.findAtPoint(point,results);
}
//-----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::findInRange(const Capsule & range, std::vector<ObjectType> & results) const
{
root.findInRange(range, results);
}
//-----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::findInRange(const Capsule & range, const SpatialSubdivisionFilter<ObjectType> &filter, std::vector<ObjectType> & results) const
{
root.findInRange(range, filter, results);
}
//-----------------------------------------------------------------------
/**
@brief Find the closest node in the sphere tree to the given point
Finds the closest object to the given point that is within maxDistance
of it. Returns true if such an object is found.
@param begin The start point
@param maxDistance The maximum distance from the start point we want to search
@param outClosest The closest item found (if one was found)
@param outDistance The distance to the closest item found
@see SphereTreeNode::findClosest()
@author Austin Appleby
*/
template<class ObjectType, class ExtentAccessor>
inline bool SphereTree<ObjectType, ExtentAccessor>::findClosest(const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance ) const
{
outMinDistance = maxDistance;
return root.findClosest(begin, maxDistance, outClosest, outMinDistance, outMaxDistance);
}
template<class ObjectType, class ExtentAccessor>
inline bool SphereTree<ObjectType, ExtentAccessor>::findClosest(const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance, int & testCounter ) const
{
outMinDistance = maxDistance;
return root.findClosest(begin, maxDistance, outClosest, outMinDistance, outMaxDistance, testCounter);
}
//-----------------------------------------------------------------------
/**
@brief Find the closest node in the sphere tree to the given point
Finds the closest (in X-Z) object to the given point that is within maxDistance
of it. Returns true if such an object is found.
@param begin The start point
@param maxDistance The maximum distance (in X-Z) from the start point we want to search
@param outClosest The closest item found (if one was found)
@param outDistance The distance to the closest item found
@see SphereTreeNode::findClosest()
@author Austin Appleby
*/
template<class ObjectType, class ExtentAccessor>
inline bool SphereTree<ObjectType, ExtentAccessor>::findClosest2d(const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance ) const
{
outMinDistance = maxDistance;
return root.findClosest2d(begin, maxDistance, outClosest, outMinDistance, outMaxDistance);
}
template<class ObjectType, class ExtentAccessor>
inline bool SphereTree<ObjectType, ExtentAccessor>::findClosest2d(const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance, int & testCounter ) const
{
outMinDistance = maxDistance;
return root.findClosest2d(begin, maxDistance, outClosest, outMinDistance, outMaxDistance, testCounter);
}
//-----------------------------------------------------------------------
/**
@brief relocate an object in the sphere tree
The sphere tree will find the SphereTreeNode that currently contains
this object. That node is specified in the SpatialSubdivisionHandle
(which is actually a SphereTreeNode::NodeHandle). If the object
remains in the node, the operation completes almost immediately.
If the object leaves it's node, it is re-intergrated in terms of the
parent nodes until a new node is located or created, and he
object handle is updated to reflect the new container node for
the object.
@param object A SphereTreeNode::handle describing the object and the
SphereTreeNode that contains the object
@param start Where the object started moving from
@param end Where the object ends up after moving
@see SpatialSubdivision::move()
@see SphereTreeNode::NodeHandle::move()
@author Justin Randall
*/
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::move(SpatialSubdivisionHandle *object)
{
if (object)
static_cast<typename SphereTreeNode<ObjectType, ExtentAccessor>::NodeHandle *>(object)->move();
}
//-----------------------------------------------------------------------
/**
@brief remove an object from the sphere tree
Advises the containing node that it no longer contains this object.
If the node is empty, then it unlinks itself from the parent node. If
the parent node becomes empty, it unlinks from it's parent. This recurses
until all empty nodes are pruned from the tree.
@param object A SphereTreeNode::NodeHandle pointer describing the
object and the SphereTreeNode that contains the object.
@see SpatialSubdivision::removeObject
@see SphereTreeNode::NodeHandle::removeObject
@author Justin Randall
*/
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::removeObject(SpatialSubdivisionHandle * object)
{
if (object)
static_cast<typename SphereTreeNode<ObjectType, ExtentAccessor>::NodeHandle *>(object)->removeObject();
}
// ----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::validate() const
{
root.validate();
}
// ----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
inline int SphereTree<ObjectType, ExtentAccessor>::getNodeCount() const
{
return root.getNodeCount();
}
// ----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
inline bool SphereTree<ObjectType, ExtentAccessor>::empty() const
{
return root.empty();
}
// ----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
inline int SphereTree<ObjectType, ExtentAccessor>::getObjectCount() const
{
return root.getObjectCount();
}
// ----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
inline void SphereTree<ObjectType, ExtentAccessor>::apply(typename SphereTreeNode<ObjectType, ExtentAccessor>::NodeFunctor N)
{
return root.apply(N);
}
//-----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
inline bool SphereTree<ObjectType, ExtentAccessor>::isWithin (Vector const & position) const
{
return root.isWithin (position);
}
// ----------------------------------------------------------------------
template<class ObjectType, class ExtentAccessor>
Sphere const &SphereTree<ObjectType, ExtentAccessor>::getRealSphere() const
{
return root.getRealSphere();
}
// ======================================================================
#endif // _INCLUDED_SphereTree_H
File diff suppressed because it is too large Load Diff

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