mirror of
https://github.com/SWG-Source/src.git
synced 2026-07-31 00:15:55 -04:00
Added sharedMath and sharedRandom libraries
This commit is contained in:
@@ -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 ¢er, real radius);
|
||||
Sphere(real x, real y, real z, real radius);
|
||||
|
||||
void setCenter(real x, real y, real z);
|
||||
void setCenter(const Vector ¢er);
|
||||
void setRadius(real radius);
|
||||
void set(const Vector ¢er, float radius);
|
||||
void set(float x, float y, float z, float radius);
|
||||
|
||||
const Vector &getCenter() const;
|
||||
const real getRadius() const;
|
||||
|
||||
Vector const & getAxisX ( void ) const;
|
||||
Vector const & getAxisY ( void ) const;
|
||||
Vector const & getAxisZ ( void ) const;
|
||||
|
||||
float getExtentX ( void ) const;
|
||||
float getExtentY ( void ) const;
|
||||
float getExtentZ ( void ) const;
|
||||
|
||||
Circle getCircle ( void ) const;
|
||||
|
||||
bool contains(const Vector &point) const;
|
||||
bool contains(const Sphere &other) const;
|
||||
|
||||
bool intersectsLine(const Vector &startPoint, const Vector &endPoint) const;
|
||||
bool intersectsLineSegment(const Vector &startPoint, const Vector &endPoint) const;
|
||||
bool intersectsRay(const Vector & startPoint, const Vector & normalizedDirection) const;
|
||||
bool intersectsSphere(const Sphere &other) const;
|
||||
bool intersectsCone(Vector const & coneBase, Vector const & coneNormal, float coneAngleRadians) const;
|
||||
Vector closestPointOnSphere(Vector const & point) const;
|
||||
Vector approximateClosestPointOnSphere(Vector const & point) const;
|
||||
|
||||
bool operator==(const Sphere & rhs) const;
|
||||
|
||||
Range getRangeX ( void ) const;
|
||||
Range getRangeY ( void ) const;
|
||||
Range getRangeZ ( void ) const;
|
||||
|
||||
private:
|
||||
|
||||
/// Center point of the sphere.
|
||||
Vector m_center;
|
||||
|
||||
/// Radius of the sphere.
|
||||
real m_radius;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
/**
|
||||
* Construct a default sphere.
|
||||
*
|
||||
* The sphere will be centered at (0,0,0) and have a radius of 0.
|
||||
*/
|
||||
|
||||
inline Sphere::Sphere()
|
||||
:
|
||||
m_center(),
|
||||
m_radius(0)
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Construct a sphere.
|
||||
*
|
||||
* @param center The center point for the sphere.
|
||||
* @param radius The radius of the sphere.
|
||||
*/
|
||||
|
||||
inline Sphere::Sphere(const Vector ¢er, real radius)
|
||||
:
|
||||
m_center(center),
|
||||
m_radius(radius)
|
||||
{
|
||||
WARNING_STRICT_FATAL(m_radius < 0.0f, ("Sphere has negative radius!"));
|
||||
if(m_radius < 0.0f)
|
||||
radius = 0.0f;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Construct a sphere
|
||||
*
|
||||
* @param x The X center point of the sphere.
|
||||
* @param y The Y center point of the sphere.
|
||||
* @param z The Z center point of the sphere.
|
||||
* @param radius The radius of the sphere.
|
||||
*/
|
||||
|
||||
inline Sphere::Sphere(real x, real y, real z, real radius)
|
||||
:
|
||||
m_center(Vector(x, y, z)),
|
||||
m_radius(radius)
|
||||
{
|
||||
WARNING_STRICT_FATAL(m_radius < 0.0f, ("Sphere has negative radius!"));
|
||||
if(m_radius < 0.0f)
|
||||
radius = 0.0f;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Set the center point of the sphere.
|
||||
*
|
||||
* @param x The new X center point of the sphere.
|
||||
* @param y The new Y center point of the sphere.
|
||||
* @param z The new Z center point of the sphere.
|
||||
*/
|
||||
|
||||
inline void Sphere::setCenter(const real x, const real y, const real z)
|
||||
{
|
||||
m_center.x = x;
|
||||
m_center.y = y;
|
||||
m_center.z = z;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Set the center point of the sphere.
|
||||
*
|
||||
* @param center The new center point of the sphere.
|
||||
*/
|
||||
|
||||
inline void Sphere::setCenter(const Vector ¢er)
|
||||
{
|
||||
m_center = center;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Set the radius of the sphere.
|
||||
*
|
||||
* @param radius The new radius of the sphere.
|
||||
*/
|
||||
|
||||
inline void Sphere::setRadius(real radius)
|
||||
{
|
||||
m_radius = radius;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline void Sphere::set(const Vector ¢er, const float radius)
|
||||
{
|
||||
m_center = center;
|
||||
m_radius = radius;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline void Sphere::set(const float x, const float y, const float z, const float radius)
|
||||
{
|
||||
m_center.x = x;
|
||||
m_center.y = y;
|
||||
m_center.z = z;
|
||||
m_radius = radius;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Get the center point of the sphere.
|
||||
*
|
||||
* @return The center point of the sphere.
|
||||
*/
|
||||
|
||||
inline const Vector &Sphere::getCenter() const
|
||||
{
|
||||
return m_center;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Get the radius of the sphere.
|
||||
*
|
||||
* @return The radius of the sphere.
|
||||
*/
|
||||
|
||||
inline const real Sphere::getRadius() const
|
||||
{
|
||||
return m_radius;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline Vector const & Sphere::getAxisX ( void ) const
|
||||
{
|
||||
return Vector::unitX;
|
||||
}
|
||||
|
||||
inline Vector const & Sphere::getAxisY ( void ) const
|
||||
{
|
||||
return Vector::unitY;
|
||||
}
|
||||
|
||||
inline Vector const & Sphere::getAxisZ ( void ) const
|
||||
{
|
||||
return Vector::unitZ;
|
||||
}
|
||||
|
||||
// ----------
|
||||
|
||||
inline float Sphere::getExtentX ( void ) const
|
||||
{
|
||||
return getRadius();
|
||||
}
|
||||
|
||||
inline float Sphere::getExtentY ( void ) const
|
||||
{
|
||||
return getRadius();
|
||||
}
|
||||
|
||||
inline float Sphere::getExtentZ ( void ) const
|
||||
{
|
||||
return getRadius();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Check if a point is inside the sphere
|
||||
*
|
||||
* @return True if the point is in the sphere, otherwise false.
|
||||
*/
|
||||
|
||||
inline bool Sphere::contains(const Vector &point) const
|
||||
{
|
||||
return m_center.magnitudeBetweenSquared(point) <= sqr(m_radius);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Check if the sphere entirely contains another sphere.
|
||||
*
|
||||
* @return True if the second sphere is entirely contained within the first.
|
||||
*/
|
||||
|
||||
inline bool Sphere::contains(const Sphere &other) const
|
||||
{
|
||||
if (other.m_radius <= m_radius)
|
||||
{
|
||||
return m_center.magnitudeBetweenSquared(other.m_center) <= sqr(m_radius - other.m_radius);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
inline bool Sphere::intersectsLine(const Vector & line0, const Vector & line1) const
|
||||
{
|
||||
return contains(m_center.findClosestPointOnLine(line0, line1));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
inline bool Sphere::intersectsLineSegment(const Vector & startPoint, const Vector & endPoint) const
|
||||
{
|
||||
return contains(m_center.findClosestPointOnLineSegment(startPoint, endPoint));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@brief determine if a ray intersects a sphere
|
||||
*/
|
||||
inline bool Sphere::intersectsRay(const Vector & startPoint, const Vector & normalizedDirection) const
|
||||
{
|
||||
// If the ray starts inside the sphere,
|
||||
// it MUST intersect the sphere
|
||||
if(contains(startPoint))
|
||||
return true;
|
||||
|
||||
// get the squre magnitude between the origin of the sphere
|
||||
// and the start point of the ray
|
||||
Vector rayStartPointToCenter = m_center - startPoint;
|
||||
|
||||
// project the ling segment described by the ray start point to the
|
||||
// sphere origin on the ray
|
||||
const float originRayDot = rayStartPointToCenter.dot(normalizedDirection);
|
||||
|
||||
if(originRayDot < 0.0f)
|
||||
{
|
||||
// Center of the sphere is 'behind' the ray, the sphere can't intersect the ray
|
||||
// without containing the start point, but since it doesn't the sphere doesn't intersect
|
||||
// the ray.
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// distanceSquared - sqr(originRayDot) = squre length of the line
|
||||
// segment from the sphere origin that is perpendicular to the ray.
|
||||
// If that length is less than the radius, there is an intersection.
|
||||
const float distanceSquared = rayStartPointToCenter.magnitudeSquared();
|
||||
const float distanceToRaySquared = sqr(m_radius) - (distanceSquared - sqr(originRayDot));
|
||||
return (distanceToRaySquared > 0.0f);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
inline bool Sphere::intersectsSphere(const Sphere & other) const
|
||||
{
|
||||
const real d = m_center.magnitudeBetweenSquared(other.getCenter());
|
||||
const real r = sqr(m_radius + other.getRadius());
|
||||
return d < r;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
inline bool Sphere::operator==(const Sphere & rhs) const
|
||||
{
|
||||
return this == &rhs || (m_radius == rhs.m_radius && m_center == rhs.m_center);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,657 @@
|
||||
// SphereTree.h
|
||||
// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved.
|
||||
// Author: Justin Randall
|
||||
|
||||
#ifndef _INCLUDED_SphereTree_H
|
||||
#define _INCLUDED_SphereTree_H
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#include "sharedMath/Sphere.h"
|
||||
#include "sharedMath/Capsule.h"
|
||||
#include "sharedMath/SpatialSubdivision.h"
|
||||
#include "sharedMath/SphereTreeNode.h"
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@brief a templatized implementation of a sphere tree.
|
||||
|
||||
A SphereTree organizes data hierarchically in sphere nodes.
|
||||
|
||||
Sphere nodes have a containment relationship, starting from the
|
||||
more general, larger sphere nodes, to smaller, more granular
|
||||
nodes which contain objects. Any node may contain objects as well
|
||||
as child nodes.
|
||||
|
||||
The tree balances itself as it discovers usable world space.
|
||||
Its depth is defined by the potential worldspace covered by the tree
|
||||
and the extent data of the objects contained within the tree.
|
||||
|
||||
The default behavior of the tree is to provide general coverage of
|
||||
world space with about 32 nodes. Child nodes follow this heuristic
|
||||
as items are inserted into the tree. Item extents (by default)
|
||||
want to be ten times smaller than a container node's maximum extent.
|
||||
If this ratio is exceeded, the object continues to fall through the
|
||||
tree until a suitable leaf node is located.
|
||||
|
||||
These heuristics may be tweaked, but generally show good behavior,
|
||||
favoring move, range, and reintegration to insertion performance.
|
||||
|
||||
In simulations with 1 million objects in a 16 cubic kilometer world
|
||||
space, the tree provides performance of over 1,000 move operations
|
||||
per millisecond.
|
||||
|
||||
How it works ---
|
||||
|
||||
INSERTING
|
||||
|
||||
When an object is first added to the SphereTree, it is passed to
|
||||
the root node, which encompasses all world space. If the object
|
||||
falls outside of the root node, the root node is expanded, and
|
||||
new max sizes for child nodes are calculated to keep the tree
|
||||
generally balanced for future operations. If the object extent
|
||||
exceeds the ratio of object-to-leaf-max size, then the maximum
|
||||
node size is again recalculated for general balancing. The first
|
||||
few insertions into the tree will trigger these recalculations,
|
||||
but have no effect on existing nodes.
|
||||
|
||||
Once the balancing calculations are done (if they were needed at
|
||||
all in the first place), the root node finds a candidate child
|
||||
node to accept the new object. If no candidate exists, a new
|
||||
child sphere is created, and the object is passed to the child.
|
||||
|
||||
The child will repeat the previous step, finding candidates
|
||||
(new nodes don't check, they don't have children), and passing
|
||||
the object further down the tree until a suitably sized child
|
||||
node contains the object.
|
||||
|
||||
The default behavior is to find child nodes that are a
|
||||
factor of 4 times smaller with each step towards the solution
|
||||
leaf node. The solution leaf must be (by default) 10 times larger
|
||||
than objects it contains.
|
||||
|
||||
An object with a 1 meter sphere in a 16 kilometer world follows
|
||||
this path: [ root -> 4k child -> 1k child -> 250 meter child ->
|
||||
62 meter child ] or a depth of 4.
|
||||
|
||||
MOVING
|
||||
|
||||
When an object moves, the destination sphere is checked against
|
||||
the containing node. If the real size of the containing node's
|
||||
sphere can contain the object, the operation is complete.
|
||||
|
||||
If the real node size cannot contain the object, then a check
|
||||
is made to see if the max size can contain the object. If it
|
||||
can, the node is resized and the operation completes.
|
||||
|
||||
If the max sphere size cannot contain the object, then the
|
||||
object is passed to the parent. If the object can be contained within
|
||||
the parent, then a candidate target node is identified and the
|
||||
object is then placed in it.
|
||||
|
||||
In most cases, the object stays within the real sphere size. The
|
||||
next most common case is the object being contained in the container
|
||||
node's max sphere. Both of these are very fast operations and
|
||||
incur little cost on the system. Re-integration is slightly more
|
||||
expensive but also not as common.
|
||||
|
||||
The worst case is that all objects warp around and must be
|
||||
fully re-integrated from the root node. This is as expensive
|
||||
as insertion plus the time required to traverse up the tree
|
||||
and check containment candidates en route to the root node.
|
||||
|
||||
The worst case simulation with 1 million objects clocked move
|
||||
operations at < 0.05 milliseconds (all 1 million objects moving to
|
||||
origin from random locations)
|
||||
|
||||
FINDING IN RANGE
|
||||
|
||||
When the SphereTree receives a find request, it queries the root
|
||||
node for all child spheres which intersect the sphere described
|
||||
by the range query (location, radius). A recursive query is
|
||||
made into child nodes which satisfy the intersection query,
|
||||
culling more candidates as the find operations solves for all objects
|
||||
intersecting the range sphere.
|
||||
|
||||
Find operations are faster for smaller range spheres, slower for
|
||||
larger spheres, averaging thousands of results per millisecond. Most
|
||||
of the time is spent filling a result vector.
|
||||
|
||||
OTHER NOTES
|
||||
|
||||
The sphere tree defines a node handle that derives from
|
||||
SpatialSubdivisionHandle. Since the superclass API defines
|
||||
operations in terms of a SpatialSubdivisionHandle, the sphere
|
||||
tree can use this handle to go directly to a leaf node for
|
||||
move operations. The application using the SphereTree merely
|
||||
needs to perform all operations (except addObject) in terms
|
||||
of the handle.
|
||||
|
||||
Tests were performed on a 700MHz P-III system with 256MB RAM running
|
||||
Windows 2000. The dev environment is MSVC.
|
||||
|
||||
SphereTree's are succesfully in use on Linux, gcc-2.95-3 on a RedHat 6.2,
|
||||
7.0 and 7.1 distributions.
|
||||
|
||||
|
||||
DEPENDENCIES
|
||||
|
||||
Sphere that defines the following:
|
||||
\code
|
||||
void setCenter(real x, real y, real z);
|
||||
void setCenter(const Vector ¢er);
|
||||
void setRadius(real radius);
|
||||
|
||||
const Vector &getCenter() const;
|
||||
const real getRadius() const;
|
||||
|
||||
bool contains(const Vector &point) const;
|
||||
bool contains(const Sphere &other) const;
|
||||
bool intersectsSphere(const Sphere &other) const;
|
||||
bool intersectsLine(const Vector &startPoint, const Vector &endPoint) const;
|
||||
bool intersectsLineSegment(const Vector &startPoint, const Vector &endPoint) const;
|
||||
bool intersectsRay(const Vector & startPoint, const Vector & normalizedDirection) const;
|
||||
\endcode
|
||||
|
||||
and Vector that defines
|
||||
\code
|
||||
real magnitudeSquared(void) const;
|
||||
real magnitude(void) const;
|
||||
real magnitudeBetween(const Vector &vector) const;
|
||||
real magnitudeBetweenSquared(const Vector &vector) const;
|
||||
const Vector findClosestPointOnLine(const Vector &line0, const Vector &line1) const;
|
||||
const Vector findClosestPointOnLineSegment(const Vector & startPoint, const Vector & endPoint) const;
|
||||
real dot(const Vector &vector) const;
|
||||
\endcode
|
||||
|
||||
These dependencies can be satisfied with the BootPrint/Sony Online Entertainment
|
||||
sharedMath library.
|
||||
|
||||
@see SpatialSubdivision
|
||||
@see SpatialSubdivisionHandle
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
class SphereTree : public SpatialSubdivision<ObjectType, Sphere, ExtentAccessor>
|
||||
{
|
||||
public:
|
||||
typedef SphereTreeNode<ObjectType, ExtentAccessor> NodeType;
|
||||
|
||||
SphereTree ();
|
||||
~SphereTree ();
|
||||
virtual SpatialSubdivisionHandle * addObject (ObjectType object);
|
||||
virtual const bool canSee (SpatialSubdivisionHandle * target, const Vector & start, const float distance, const float fov=0.0f) const;
|
||||
void dumpSphereTreeObjects(std::vector<ObjectType> & results) const;
|
||||
void dumpSphereTree (std::vector<std::pair<ObjectType, Sphere> > & results) const;
|
||||
void dumpSphereTreeNodes(std::vector<std::pair<ObjectType, Sphere> > & results) const;
|
||||
void dumpSphereTreeObjs (std::vector<std::pair<ObjectType, Sphere> > & results) const;
|
||||
void dumpEdgeList (std::vector<Vector> & results) const;
|
||||
virtual void findInRange (const Vector & origin, const float distance, std::vector<ObjectType> & results) const;
|
||||
virtual void findInRange (const Vector & origin, const float distance, std::vector<ObjectType> & results, int & testCounter) const;
|
||||
virtual void findInRange (const Vector & origin, const float distance, const SpatialSubdivisionFilter<ObjectType> &filter, std::vector<ObjectType> & results) const;
|
||||
virtual void findInRange (const Vector & origin, const float distance, const SpatialSubdivisionFilter<ObjectType> &filter, std::vector<ObjectType> & results, int & testCounter) const;
|
||||
virtual void findOnRay (const Vector & begin, const Vector & dir, std::vector<ObjectType> & results) const;
|
||||
virtual void findOnSegment (const Vector & begin, const Vector & end, std::vector<ObjectType> & results) const;
|
||||
virtual void findOnSegment(Vector const & begin, Vector const & end, SpatialSubdivisionFilter<ObjectType> const & filter, std::vector<ObjectType> & results) const;
|
||||
virtual void findAtPoint (const Vector & point, std::vector<ObjectType> & results) const;
|
||||
virtual void findInRange (const Capsule & range, std::vector<ObjectType> & results) const;
|
||||
virtual void findInRange (const Capsule & range, const SpatialSubdivisionFilter<ObjectType> &filter, std::vector<ObjectType> & results) const;
|
||||
virtual bool findClosest (const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance) const;
|
||||
virtual bool findClosest (const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance, int & testCounter) const;
|
||||
virtual bool findClosest2d (const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance) const;
|
||||
virtual bool findClosest2d (const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance, int & testCounter) const;
|
||||
virtual void move (SpatialSubdivisionHandle * object);
|
||||
virtual void removeObject (SpatialSubdivisionHandle * object);
|
||||
virtual void validate () const;
|
||||
virtual int getNodeCount () const;
|
||||
bool empty () const;
|
||||
virtual int getObjectCount () const;
|
||||
|
||||
void apply (typename SphereTreeNode<ObjectType,ExtentAccessor>::NodeFunctor N);
|
||||
|
||||
bool isWithin (Vector const & position) const;
|
||||
Sphere const & getRealSphere () const;
|
||||
|
||||
private:
|
||||
SphereTree & operator = (const SphereTree & rhs);
|
||||
SphereTree (const SphereTree & source);
|
||||
private:
|
||||
NodeType root;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@brief construct a sphere tree
|
||||
|
||||
Initializes the root node with no parent.
|
||||
|
||||
ExtentAccessor is defined in terms of a struct with a
|
||||
getExtent(ObjectType) member function that returns a Sphere.
|
||||
*/
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline SphereTree<ObjectType, ExtentAccessor>::SphereTree() :
|
||||
root()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@brief destroy the sphere tree
|
||||
|
||||
Doesn't do anything. Included here for completeness.
|
||||
*/
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline SphereTree<ObjectType, ExtentAccessor>::~SphereTree()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@brief add an object to the sphere tree
|
||||
|
||||
Calls addObject on the root node.
|
||||
|
||||
@see SphereTreeNode
|
||||
@see SpatialSubdivision::addObject(ObjectType object)
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline SpatialSubdivisionHandle * SphereTree<ObjectType, ExtentAccessor>::addObject(ObjectType object)
|
||||
{
|
||||
return root.addObject(object);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@brief not implemented
|
||||
|
||||
@todo implement!
|
||||
*/
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline const bool SphereTree<ObjectType, ExtentAccessor>::canSee(SpatialSubdivisionHandle * target, const Vector & start, const float distance, const float fov) const
|
||||
{
|
||||
UNREF(target);
|
||||
UNREF(start);
|
||||
UNREF(distance);
|
||||
UNREF(fov);
|
||||
|
||||
//@todo implement
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline void SphereTree<ObjectType, ExtentAccessor>::dumpSphereTreeObjects(std::vector<ObjectType> & results) const
|
||||
{
|
||||
root.dumpSphereTreeObjects(results);
|
||||
}
|
||||
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline void SphereTree<ObjectType, ExtentAccessor>::dumpSphereTree(std::vector<std::pair<ObjectType, Sphere> > & results) const
|
||||
{
|
||||
root.dumpSphereTree(results);
|
||||
}
|
||||
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline void SphereTree<ObjectType, ExtentAccessor>::dumpSphereTreeNodes(std::vector<std::pair<ObjectType, Sphere> > & results) const
|
||||
{
|
||||
root.dumpSphereTreeNodes(results);
|
||||
}
|
||||
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline void SphereTree<ObjectType, ExtentAccessor>::dumpSphereTreeObjs(std::vector<std::pair<ObjectType, Sphere> > & results) const
|
||||
{
|
||||
root.dumpSphereTreeObjs(results);
|
||||
}
|
||||
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline void SphereTree<ObjectType, ExtentAccessor>::dumpEdgeList(std::vector<Vector>& results) const
|
||||
{
|
||||
root.dumpEdgeList(results);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@brief find all objects contained in a sphere defined by the range params
|
||||
|
||||
Finds all objects intersecting the sphere described by the origin and
|
||||
distance parameters. The results are placed in the results vector.
|
||||
|
||||
@param origin A point describing the center of the range query
|
||||
@param distance The radius of the query. The origin and distance
|
||||
are used to create a Sphere at 'origin' with radius
|
||||
'distance'
|
||||
@param results A user supplied vector of ObjectType that will receive
|
||||
the solution to the range query.
|
||||
|
||||
@see SpatialSubdivision::findInRange()
|
||||
@see SphereTreeNode::findInRange()
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline void SphereTree<ObjectType, ExtentAccessor>::findInRange(const Vector & origin, const float distance, std::vector<ObjectType> & results) const
|
||||
{
|
||||
const Sphere range(origin, distance);
|
||||
root.findInRange(range, results);
|
||||
}
|
||||
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline void SphereTree<ObjectType, ExtentAccessor>::findInRange(const Vector & origin, const float distance, std::vector<ObjectType> & results, int & testCounter) const
|
||||
{
|
||||
const Sphere range(origin, distance);
|
||||
root.findInRange(range, results, testCounter);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@brief find all objects contained in a sphere defined by the range params
|
||||
which meet a filter criteria
|
||||
|
||||
Finds all objects intersecting the sphere described by the origin and
|
||||
distance parameters. The results are placed in the results vector.
|
||||
|
||||
@param origin A point describing the center of the range query
|
||||
@param distance The radius of the query. The origin and distance
|
||||
are used to create a Sphere at 'origin' with radius
|
||||
'distance'
|
||||
@param filter A user supplied filter functor.
|
||||
filter.operator(const ObjectType & object) should return
|
||||
true if the object is to be returned.
|
||||
@param results A user supplied vector of ObjectType that will receive
|
||||
the solution to the range query.
|
||||
|
||||
@see SpatialSubdivision::findInRange()
|
||||
@see SphereTreeNode::findInRange()
|
||||
|
||||
@author Acy Stapp
|
||||
*/
|
||||
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline void SphereTree<ObjectType, ExtentAccessor>::findInRange(const Vector & origin, const float distance, const SpatialSubdivisionFilter<ObjectType> &filter, std::vector<ObjectType> & results) const
|
||||
{
|
||||
const Sphere range(origin, distance);
|
||||
root.findInRange(range, filter, results);
|
||||
}
|
||||
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline void SphereTree<ObjectType, ExtentAccessor>::findInRange(const Vector & origin, const float distance, const SpatialSubdivisionFilter<ObjectType> &filter, std::vector<ObjectType> & results, int & testCounter) const
|
||||
{
|
||||
const Sphere range(origin, distance);
|
||||
root.findInRange(range, filter, results, testCounter);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@brief find all objects that hit the given ray
|
||||
|
||||
Finds all objects intersecting the ray described by the start point
|
||||
and direction parameters. The results are placed in the results vector.
|
||||
|
||||
@param begin A point describing the origin of the ray query
|
||||
@param dir A vector describing the direction of the ray
|
||||
@param results A user supplied vector of ObjectType that will receive the results of the query.
|
||||
|
||||
@see SpatialSubdivision::findOnRay()
|
||||
@see SphereTreeNode::findOnRay()
|
||||
|
||||
@author Austin Appleby
|
||||
*/
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline void SphereTree<ObjectType, ExtentAccessor>::findOnRay(const Vector & begin, const Vector & dir, std::vector<ObjectType> & results) const
|
||||
{
|
||||
Vector normDir = dir;
|
||||
IGNORE_RETURN( normDir.normalize() );
|
||||
|
||||
root.findOnRay(begin, normDir, results);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@brief find all objects that hit the given segment
|
||||
|
||||
Finds all objects intersecting the segment described by the start point
|
||||
and end point parameters. The results are placed in the results vector.
|
||||
|
||||
@param begin The start point of the test segment
|
||||
@param dir The end point of the test segment
|
||||
@param results A user supplied vector of ObjectType that will receive the results of the query.
|
||||
|
||||
@see SpatialSubdivision::findOnSegment()
|
||||
@see SphereTreeNode::findOnSegment()
|
||||
|
||||
@author Austin Appleby
|
||||
*/
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline void SphereTree<ObjectType, ExtentAccessor>::findOnSegment(const Vector & begin, const Vector & end, std::vector<ObjectType> & results) const
|
||||
{
|
||||
root.findOnSegment(begin, end, results);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline void SphereTree<ObjectType, ExtentAccessor>::findOnSegment(Vector const & begin, Vector const & end, SpatialSubdivisionFilter<ObjectType> const & filter, std::vector<ObjectType> & results) const
|
||||
{
|
||||
root.findOnSegment(begin, end, filter, results);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@brief find all objects that hit the given segment
|
||||
|
||||
Finds all objects overlapping the given point.
|
||||
The results are placed in the results vector.
|
||||
|
||||
@param begin The start point of the test segment
|
||||
@param dir The end point of the test segment
|
||||
@param results A user supplied vector of ObjectType that will receive the results of the query.
|
||||
|
||||
@see SpatialSubdivision::findOnSegment()
|
||||
@see SphereTreeNode::findOnSegment()
|
||||
|
||||
@author Austin Appleby
|
||||
*/
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline void SphereTree<ObjectType, ExtentAccessor>::findAtPoint(const Vector & point, std::vector<ObjectType> & results) const
|
||||
{
|
||||
root.findAtPoint(point,results);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline void SphereTree<ObjectType, ExtentAccessor>::findInRange(const Capsule & range, std::vector<ObjectType> & results) const
|
||||
{
|
||||
root.findInRange(range, results);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline void SphereTree<ObjectType, ExtentAccessor>::findInRange(const Capsule & range, const SpatialSubdivisionFilter<ObjectType> &filter, std::vector<ObjectType> & results) const
|
||||
{
|
||||
root.findInRange(range, filter, results);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@brief Find the closest node in the sphere tree to the given point
|
||||
|
||||
Finds the closest object to the given point that is within maxDistance
|
||||
of it. Returns true if such an object is found.
|
||||
|
||||
@param begin The start point
|
||||
@param maxDistance The maximum distance from the start point we want to search
|
||||
@param outClosest The closest item found (if one was found)
|
||||
@param outDistance The distance to the closest item found
|
||||
|
||||
@see SphereTreeNode::findClosest()
|
||||
|
||||
@author Austin Appleby
|
||||
*/
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline bool SphereTree<ObjectType, ExtentAccessor>::findClosest(const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance ) const
|
||||
{
|
||||
outMinDistance = maxDistance;
|
||||
|
||||
return root.findClosest(begin, maxDistance, outClosest, outMinDistance, outMaxDistance);
|
||||
}
|
||||
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline bool SphereTree<ObjectType, ExtentAccessor>::findClosest(const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance, int & testCounter ) const
|
||||
{
|
||||
outMinDistance = maxDistance;
|
||||
|
||||
return root.findClosest(begin, maxDistance, outClosest, outMinDistance, outMaxDistance, testCounter);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@brief Find the closest node in the sphere tree to the given point
|
||||
|
||||
Finds the closest (in X-Z) object to the given point that is within maxDistance
|
||||
of it. Returns true if such an object is found.
|
||||
|
||||
@param begin The start point
|
||||
@param maxDistance The maximum distance (in X-Z) from the start point we want to search
|
||||
@param outClosest The closest item found (if one was found)
|
||||
@param outDistance The distance to the closest item found
|
||||
|
||||
@see SphereTreeNode::findClosest()
|
||||
|
||||
@author Austin Appleby
|
||||
*/
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline bool SphereTree<ObjectType, ExtentAccessor>::findClosest2d(const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance ) const
|
||||
{
|
||||
outMinDistance = maxDistance;
|
||||
|
||||
return root.findClosest2d(begin, maxDistance, outClosest, outMinDistance, outMaxDistance);
|
||||
}
|
||||
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline bool SphereTree<ObjectType, ExtentAccessor>::findClosest2d(const Vector & begin, const float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance, int & testCounter ) const
|
||||
{
|
||||
outMinDistance = maxDistance;
|
||||
|
||||
return root.findClosest2d(begin, maxDistance, outClosest, outMinDistance, outMaxDistance, testCounter);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@brief relocate an object in the sphere tree
|
||||
|
||||
The sphere tree will find the SphereTreeNode that currently contains
|
||||
this object. That node is specified in the SpatialSubdivisionHandle
|
||||
(which is actually a SphereTreeNode::NodeHandle). If the object
|
||||
remains in the node, the operation completes almost immediately.
|
||||
If the object leaves it's node, it is re-intergrated in terms of the
|
||||
parent nodes until a new node is located or created, and he
|
||||
object handle is updated to reflect the new container node for
|
||||
the object.
|
||||
|
||||
@param object A SphereTreeNode::handle describing the object and the
|
||||
SphereTreeNode that contains the object
|
||||
@param start Where the object started moving from
|
||||
@param end Where the object ends up after moving
|
||||
|
||||
@see SpatialSubdivision::move()
|
||||
@see SphereTreeNode::NodeHandle::move()
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline void SphereTree<ObjectType, ExtentAccessor>::move(SpatialSubdivisionHandle *object)
|
||||
{
|
||||
if (object)
|
||||
static_cast<typename SphereTreeNode<ObjectType, ExtentAccessor>::NodeHandle *>(object)->move();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
@brief remove an object from the sphere tree
|
||||
|
||||
Advises the containing node that it no longer contains this object.
|
||||
If the node is empty, then it unlinks itself from the parent node. If
|
||||
the parent node becomes empty, it unlinks from it's parent. This recurses
|
||||
until all empty nodes are pruned from the tree.
|
||||
|
||||
@param object A SphereTreeNode::NodeHandle pointer describing the
|
||||
object and the SphereTreeNode that contains the object.
|
||||
|
||||
@see SpatialSubdivision::removeObject
|
||||
@see SphereTreeNode::NodeHandle::removeObject
|
||||
|
||||
@author Justin Randall
|
||||
*/
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline void SphereTree<ObjectType, ExtentAccessor>::removeObject(SpatialSubdivisionHandle * object)
|
||||
{
|
||||
if (object)
|
||||
static_cast<typename SphereTreeNode<ObjectType, ExtentAccessor>::NodeHandle *>(object)->removeObject();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline void SphereTree<ObjectType, ExtentAccessor>::validate() const
|
||||
{
|
||||
root.validate();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline int SphereTree<ObjectType, ExtentAccessor>::getNodeCount() const
|
||||
{
|
||||
return root.getNodeCount();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline bool SphereTree<ObjectType, ExtentAccessor>::empty() const
|
||||
{
|
||||
return root.empty();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline int SphereTree<ObjectType, ExtentAccessor>::getObjectCount() const
|
||||
{
|
||||
return root.getObjectCount();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline void SphereTree<ObjectType, ExtentAccessor>::apply(typename SphereTreeNode<ObjectType, ExtentAccessor>::NodeFunctor N)
|
||||
{
|
||||
return root.apply(N);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
inline bool SphereTree<ObjectType, ExtentAccessor>::isWithin (Vector const & position) const
|
||||
{
|
||||
return root.isWithin (position);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
template<class ObjectType, class ExtentAccessor>
|
||||
Sphere const &SphereTree<ObjectType, ExtentAccessor>::getRealSphere() const
|
||||
{
|
||||
return root.getRealSphere();
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif // _INCLUDED_SphereTree_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,889 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Transform.cpp
|
||||
// jeff grills
|
||||
//
|
||||
// copyright 1998 Bootprint Entertainment
|
||||
//
|
||||
// matrix multiply
|
||||
//
|
||||
// a b c d m n o p am+bq+cu an+br+cv ao+bs+cw ap+bt+cx+d
|
||||
// e f g h q r s t em+fq+gu en+fr+gv eo+fs+gw ep+ft+gx+h
|
||||
// i j k l * u v w x = im+jq+ku in+jr+kv io+js+kw ip+jt+kx+l
|
||||
// 0 0 0 1 0 0 0 1 0 0 0 1
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedMath/FirstSharedMath.h"
|
||||
#include "sharedMath/Transform.h"
|
||||
|
||||
#include "sharedDebug/DebugFlags.h"
|
||||
#include "sharedFoundation/ExitChain.h"
|
||||
#include "sharedMath/Quaternion.h"
|
||||
|
||||
#undef TRY_FOR_SSE
|
||||
#define TRY_FOR_SSE WIN32
|
||||
|
||||
#if TRY_FOR_SSE
|
||||
#include "sharedMath/SseMath.h"
|
||||
#endif
|
||||
|
||||
#include <cfloat>
|
||||
|
||||
// ======================================================================
|
||||
|
||||
static void xf_matrix_3x4(float *out, const float *left, const float *right);
|
||||
#if TRY_FOR_SSE
|
||||
static void sse_xf_matrix_3x4(float *out, const float *left, const float *right);
|
||||
#endif
|
||||
// ======================================================================
|
||||
|
||||
namespace TransformNamespace
|
||||
{
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
void remove();
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
bool s_installed;
|
||||
|
||||
typedef void (*pf_multiply)(float *out, const float *left, const float *right);
|
||||
|
||||
static pf_multiply s_mult_func;
|
||||
}
|
||||
|
||||
using namespace TransformNamespace;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
const Transform Transform::identity;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void TransformNamespace::remove()
|
||||
{
|
||||
DEBUG_FATAL(!s_installed, ("Transform not installed."));
|
||||
s_installed = false;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void Transform::install()
|
||||
{
|
||||
DEBUG_FATAL(s_installed, ("Transform already installed."));
|
||||
#if TRY_FOR_SSE
|
||||
if (SseMath::canDoSseMath())
|
||||
{
|
||||
s_mult_func = sse_xf_matrix_3x4;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_mult_func = xf_matrix_3x4;
|
||||
}
|
||||
#else
|
||||
s_mult_func = xf_matrix_3x4;
|
||||
#endif
|
||||
|
||||
s_installed = true;
|
||||
ExitChain::add(remove, "Transform");
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// Yaw this transform
|
||||
//
|
||||
// Remarks:
|
||||
//
|
||||
// This routine will rotate the transform around the Y axis by the specified
|
||||
// number of radians.
|
||||
//
|
||||
// Positive rotations are clockwise when viewed looking at the origin from
|
||||
// the positive side of the axis around which the transform is being rotated.
|
||||
//
|
||||
// See Also:
|
||||
//
|
||||
// Transform::pitch_l(), Transform::roll_l(),
|
||||
|
||||
void Transform::yaw_l(
|
||||
real radians // Amount to rotate, in radians
|
||||
)
|
||||
{
|
||||
// a b c d C 0 S 0 aC-cS b aS+cC d
|
||||
// e f g h * 0 1 0 0 = eC-gS f es+gC h
|
||||
// i j k l -S 0 C 0 iC-kS j iS+kS l
|
||||
// 0 0 0 1 0 0 0 1 0 0 0 1
|
||||
|
||||
const real sine = sin(radians);
|
||||
const real cosine = cos(radians);
|
||||
|
||||
const real a = matrix[0][0];
|
||||
const real c = matrix[0][2];
|
||||
const real e = matrix[1][0];
|
||||
const real g = matrix[1][2];
|
||||
const real i = matrix[2][0];
|
||||
const real k = matrix[2][2];
|
||||
|
||||
matrix[0][0] = a * cosine + c * -sine;
|
||||
matrix[0][2] = a * sine + c * cosine;
|
||||
|
||||
matrix[1][0] = e * cosine + g * -sine;
|
||||
matrix[1][2] = e * sine + g * cosine;
|
||||
|
||||
matrix[2][0] = i * cosine + k * -sine;
|
||||
matrix[2][2] = i * sine + k * cosine;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Pitch this transform.
|
||||
*
|
||||
* This routine will rotate the transform around the X axis by the specified
|
||||
* number of radians.
|
||||
*
|
||||
* Positive rotations are clockwise when viewed looking at the origin from
|
||||
* the positive side of the axis around which the transform is being rotated.
|
||||
*
|
||||
* @param radians Amount to rotate, in radians
|
||||
* @see Transform::yaw_l(), Transform::roll_l(),
|
||||
*/
|
||||
|
||||
void Transform::pitch_l(real radians)
|
||||
{
|
||||
// a b c d 1 0 0 0 a bC+cS -bS+cC d
|
||||
// e f g h * 0 C -S 0 = e fC+gS -fS+gC h
|
||||
// i j k l 0 S C 0 i jC+kS -jS+kC l
|
||||
// 0 0 0 1 0 0 0 1 0 0 0 1
|
||||
|
||||
const real sine = sin(radians);
|
||||
const real cosine = cos(radians);
|
||||
|
||||
const real b = matrix[0][1];
|
||||
const real c = matrix[0][2];
|
||||
const real f = matrix[1][1];
|
||||
const real g = matrix[1][2];
|
||||
const real j = matrix[2][1];
|
||||
const real k = matrix[2][2];
|
||||
|
||||
matrix[0][1] = b * cosine + c * sine;
|
||||
matrix[0][2] = b * -sine + c * cosine;
|
||||
|
||||
matrix[1][1] = f * cosine + g * sine;
|
||||
matrix[1][2] = f * -sine + g * cosine;
|
||||
|
||||
matrix[2][1] = j * cosine + k * sine;
|
||||
matrix[2][2] = j * -sine + k * cosine;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Roll this transform.
|
||||
*
|
||||
* This routine will rotate the transform around the Z axis by the specified
|
||||
* number of radians.
|
||||
*
|
||||
* Positive rotations are clockwise when viewed looking at the origin from
|
||||
* the positive side of the axis around which the transform is being rotated.
|
||||
*
|
||||
* @param radians Amount to rotate, in radians
|
||||
* @see Transform::yaw_l(), Transform::pitch_l(),
|
||||
*/
|
||||
|
||||
void Transform::roll_l(real radians)
|
||||
{
|
||||
// a b c d C -S 0 0 aC+bS -aS+bC c d
|
||||
// e f g h * S C 0 0 = eC+fS -eS+fC g h
|
||||
// i j k l 0 0 1 0 iC+jS -iS+jC k l
|
||||
// 0 0 0 1 0 0 0 1 0 0 0 1
|
||||
|
||||
const real sine = sin(radians);
|
||||
const real cosine = cos(radians);
|
||||
|
||||
const real a = matrix[0][0];
|
||||
const real b = matrix[0][1];
|
||||
const real e = matrix[1][0];
|
||||
const real f = matrix[1][1];
|
||||
const real i = matrix[2][0];
|
||||
const real j = matrix[2][1];
|
||||
|
||||
matrix[0][0] = a * cosine + b * sine;
|
||||
matrix[0][1] = a * -sine + b * cosine;
|
||||
|
||||
matrix[1][0] = e * cosine + f * sine;
|
||||
matrix[1][1] = e * -sine + f * cosine;
|
||||
|
||||
matrix[2][0] = i * cosine + j * sine;
|
||||
matrix[2][1] = i * -sine + j * cosine;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
static void xf_matrix_3x4(float *out, const float *left, const float *right)
|
||||
{
|
||||
if (left==out || right==out)
|
||||
{
|
||||
float temp[12];
|
||||
|
||||
temp[0] = left[0] * right[0] + left[1] * right[4] + left[2] * right[8];
|
||||
temp[1] = left[0] * right[1] + left[1] * right[5] + left[2] * right[9];
|
||||
temp[2] = left[0] * right[2] + left[1] * right[6] + left[2] * right[10];
|
||||
temp[3] = left[0] * right[3] + left[1] * right[7] + left[2] * right[11] + left[3];
|
||||
|
||||
temp[4] = left[4] * right[0] + left[5] * right[4] + left[6] * right[8];
|
||||
temp[5] = left[4] * right[1] + left[5] * right[5] + left[6] * right[9];
|
||||
temp[6] = left[4] * right[2] + left[5] * right[6] + left[6] * right[10];
|
||||
temp[7] = left[4] * right[3] + left[5] * right[7] + left[6] * right[11] + left[7];
|
||||
|
||||
temp[8] = left[8] * right[0] + left[9] * right[4] + left[10] * right[8];
|
||||
temp[9] = left[8] * right[1] + left[9] * right[5] + left[10] * right[9];
|
||||
temp[10]= left[8] * right[2] + left[9] * right[6] + left[10] * right[10];
|
||||
temp[11]= left[8] * right[3] + left[9] * right[7] + left[10] * right[11] + left[11];
|
||||
|
||||
out[0]=temp[0];
|
||||
out[1]=temp[1];
|
||||
out[2]=temp[2];
|
||||
out[3]=temp[3];
|
||||
out[4]=temp[4];
|
||||
out[5]=temp[5];
|
||||
out[6]=temp[6];
|
||||
out[7]=temp[7];
|
||||
out[8]=temp[8];
|
||||
out[9]=temp[9];
|
||||
out[10]=temp[10];
|
||||
out[11]=temp[11];
|
||||
}
|
||||
else
|
||||
{
|
||||
out[0] = left[0] * right[0] + left[1] * right[4] + left[2] * right[8];
|
||||
out[1] = left[0] * right[1] + left[1] * right[5] + left[2] * right[9];
|
||||
out[2] = left[0] * right[2] + left[1] * right[6] + left[2] * right[10];
|
||||
out[3] = left[0] * right[3] + left[1] * right[7] + left[2] * right[11] + left[3];
|
||||
|
||||
out[4] = left[4] * right[0] + left[5] * right[4] + left[6] * right[8];
|
||||
out[5] = left[4] * right[1] + left[5] * right[5] + left[6] * right[9];
|
||||
out[6] = left[4] * right[2] + left[5] * right[6] + left[6] * right[10];
|
||||
out[7] = left[4] * right[3] + left[5] * right[7] + left[6] * right[11] + left[7];
|
||||
|
||||
out[8] = left[8] * right[0] + left[9] * right[4] + left[10] * right[8];
|
||||
out[9] = left[8] * right[1] + left[9] * right[5] + left[10] * right[9];
|
||||
out[10]= left[8] * right[2] + left[9] * right[6] + left[10] * right[10];
|
||||
out[11]= left[8] * right[3] + left[9] * right[7] + left[10] * right[11] + left[11];
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#if TRY_FOR_SSE
|
||||
__declspec(naked) void sse_xf_matrix_3x4(float *out, const float *left, const float *right)
|
||||
{
|
||||
UNREF(left);
|
||||
UNREF(right);
|
||||
UNREF(out);
|
||||
__asm {
|
||||
push eax
|
||||
push ebx
|
||||
add esp, -48
|
||||
|
||||
// [esp + 60] == out
|
||||
// [esp + 64] == left
|
||||
// [esp + 68] == right
|
||||
mov eax, [esp + 64] // left
|
||||
mov ebx, [esp + 68] // right
|
||||
|
||||
movups xmm0, [ebx + 0] // right: row0
|
||||
movups xmm1, [ebx + 16] // right: row1
|
||||
movups xmm2, [ebx + 32] // right: row2
|
||||
|
||||
// 16-byte align data pointer
|
||||
lea ebx, [esp+15]
|
||||
and ebx, -16
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
movaps xmm3, xmm0 // right: row0
|
||||
movss xmm4, [eax + 0] // left[0][0]
|
||||
shufps xmm4, xmm4, 0
|
||||
mulps xmm3, xmm4
|
||||
|
||||
movaps xmm5, xmm1 // right: row1
|
||||
movss xmm6, [eax + 4] // left[0][1]
|
||||
shufps xmm6, xmm6, 0
|
||||
mulps xmm5, xmm6
|
||||
|
||||
addps xmm5, xmm3
|
||||
|
||||
movaps xmm3, xmm2 // right: row2
|
||||
movss xmm4, [eax + 8] // left[0][2]
|
||||
shufps xmm4, xmm4, 0
|
||||
mulps xmm3, xmm4
|
||||
|
||||
addps xmm5, xmm3
|
||||
|
||||
movss xmm7, [eax + 12] // left[0][3]
|
||||
shufps xmm7, xmm7, 0x15 //0001 0101
|
||||
addps xmm5, xmm7
|
||||
|
||||
movaps [ebx], xmm5
|
||||
///////////////////////////////////////////////////
|
||||
movaps xmm3, xmm0 // right: row0
|
||||
movss xmm4, [eax + 16] // left[1][0]
|
||||
shufps xmm4, xmm4, 0
|
||||
mulps xmm3, xmm4
|
||||
|
||||
movaps xmm5, xmm1 // right: row1
|
||||
movss xmm6, [eax + 20] // left[1][1]
|
||||
shufps xmm6, xmm6, 0
|
||||
mulps xmm5, xmm6
|
||||
|
||||
addps xmm5, xmm3
|
||||
|
||||
movaps xmm3, xmm2 // right: row2
|
||||
movss xmm4, [eax + 24] // left[1][2]
|
||||
shufps xmm4, xmm4, 0
|
||||
mulps xmm3, xmm4
|
||||
|
||||
addps xmm5, xmm3
|
||||
|
||||
movss xmm7, [eax + 28] // left[1][3]
|
||||
shufps xmm7, xmm7, 0x15 //0001 0101
|
||||
addps xmm5, xmm7
|
||||
|
||||
movaps [ebx+16], xmm5
|
||||
///////////////////////////////////////////////////
|
||||
movaps xmm3, xmm0 // right: row0
|
||||
movss xmm4, [eax + 32] // left[2][0]
|
||||
shufps xmm4, xmm4, 0
|
||||
mulps xmm3, xmm4
|
||||
|
||||
movaps xmm5, xmm1 // right: row1
|
||||
movss xmm6, [eax + 36] // left[2][1]
|
||||
shufps xmm6, xmm6, 0
|
||||
mulps xmm5, xmm6
|
||||
|
||||
addps xmm5, xmm3
|
||||
|
||||
movaps xmm3, xmm2 // right: row2
|
||||
movss xmm4, [eax + 40] // left[2][2]
|
||||
shufps xmm4, xmm4, 0
|
||||
mulps xmm3, xmm4
|
||||
|
||||
addps xmm5, xmm3
|
||||
|
||||
movss xmm7, [eax + 44] // left[2][3]
|
||||
shufps xmm7, xmm7, 0x15 //0001 0101
|
||||
addps xmm5, xmm7
|
||||
|
||||
mov eax, [esp+60]
|
||||
|
||||
movups [eax+32], xmm5
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
movaps xmm1, [ebx+ 0]
|
||||
movaps xmm2, [ebx+16]
|
||||
movups [eax+0 ], xmm1
|
||||
movups [eax+16], xmm2
|
||||
|
||||
mov ebx, [esp + 48]
|
||||
mov eax, [esp + 52]
|
||||
add esp, 56
|
||||
ret
|
||||
}
|
||||
}
|
||||
#endif
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Multiply two matrices together.
|
||||
*
|
||||
* This routine will properly handle the case where the destination matrix
|
||||
* is also one or both of the source matrices.
|
||||
*
|
||||
* @param lhs Transform on the left-hand side
|
||||
* @param rhs Transform on the right-hand side
|
||||
*/
|
||||
|
||||
void Transform::multiply(const Transform &lhs, const Transform &rhs)
|
||||
{
|
||||
s_mult_func(matrix[0], lhs.matrix[0], rhs.matrix[0]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Invert a simple transform.
|
||||
*
|
||||
* The source matrix has to be composed of purely rotational and translational
|
||||
* components. It may not contain any scaling or shearing transforms.
|
||||
*
|
||||
* @param transform Simple transform to invert
|
||||
*/
|
||||
|
||||
void Transform::invert(const Transform &transform)
|
||||
{
|
||||
// transpose the upper 3x3 matrix
|
||||
matrix[0][0] = transform.matrix[0][0];
|
||||
matrix[0][1] = transform.matrix[1][0];
|
||||
matrix[0][2] = transform.matrix[2][0];
|
||||
|
||||
matrix[1][0] = transform.matrix[0][1];
|
||||
matrix[1][1] = transform.matrix[1][1];
|
||||
matrix[1][2] = transform.matrix[2][1];
|
||||
|
||||
matrix[2][0] = transform.matrix[0][2];
|
||||
matrix[2][1] = transform.matrix[1][2];
|
||||
matrix[2][2] = transform.matrix[2][2];
|
||||
|
||||
// invert the translation
|
||||
const real x = transform.matrix[0][3];
|
||||
const real y = transform.matrix[1][3];
|
||||
const real z = transform.matrix[2][3];
|
||||
matrix[0][3] = -(matrix[0][0] * x + matrix[0][1] * y + matrix[0][2] * z);
|
||||
matrix[1][3] = -(matrix[1][0] * x + matrix[1][1] * y + matrix[1][2] * z);
|
||||
matrix[2][3] = -(matrix[2][0] * x + matrix[2][1] * y + matrix[2][2] * z);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Reorthogonalize a transform.
|
||||
*
|
||||
* Repeated rotations will introduce numerical error into the transform,
|
||||
* which will cause the upper 3x3 matrix to become non-orthonormal. If
|
||||
* enough error is introduced, weird errors will begin to occur when using
|
||||
* the transform.
|
||||
*
|
||||
* This routine attempts to reduce the numerical error by reorthonormalizing
|
||||
* the upper 3x3 matrix.
|
||||
*/
|
||||
|
||||
void Transform::reorthonormalize(void)
|
||||
{
|
||||
Vector k = getLocalFrameK_p();
|
||||
Vector j = getLocalFrameJ_p();
|
||||
|
||||
if (!k.normalize())
|
||||
{
|
||||
DEBUG_FATAL(true, ("could not normalize frame k"));
|
||||
k = Vector::unitZ; //lint !e527 // Unreachable
|
||||
}
|
||||
|
||||
if (!j.normalize())
|
||||
{
|
||||
DEBUG_FATAL(true, ("could not normalize frame j"));
|
||||
j = Vector::unitY; //lint !e527 // Unreachable
|
||||
}
|
||||
|
||||
// build the remaining vector with the cross product
|
||||
Vector i = j.cross(k);
|
||||
|
||||
// use that result to rebuild the
|
||||
j = k.cross(i);
|
||||
|
||||
// copy the results back into the transform
|
||||
matrix[0][0] = i.x;
|
||||
matrix[1][0] = i.y;
|
||||
matrix[2][0] = i.z;
|
||||
|
||||
matrix[0][1] = j.x;
|
||||
matrix[1][1] = j.y;
|
||||
matrix[2][1] = j.z;
|
||||
|
||||
matrix[0][2] = k.x;
|
||||
matrix[1][2] = k.y;
|
||||
matrix[2][2] = k.z;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Send this transform to the DebugPrint system.
|
||||
*
|
||||
* The header parameter may be NULL.
|
||||
*
|
||||
* @param header Header for the transform
|
||||
*/
|
||||
|
||||
void Transform::debugPrint(const char *header) const
|
||||
{
|
||||
if (header)
|
||||
DEBUG_REPORT_PRINT(true, ("%s\n", header));
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
DEBUG_REPORT_PRINT(true, (" %-8.2f %-8.2f %-8.2f %-8.2f\n", matrix[i][0], matrix[i][1], matrix[i][2], matrix[i][3]));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Rotate an array of vector from the matrix's current frame to the parent frame.
|
||||
*
|
||||
* Pure rotation is most useful for vectors that are orientational, such as
|
||||
* normals.
|
||||
*
|
||||
* The source and result arrays may be the same array.
|
||||
*
|
||||
* @param source Source array of vectors to transform
|
||||
* @param result Array to store the result of the transforms
|
||||
* @param count Number of vertices to transform
|
||||
* @see Transform::rotateTranslate_l2p(), Transform::rotate_p2l()
|
||||
*/
|
||||
|
||||
void Transform::rotate_l2p(const Vector *source, Vector *result, int count) const
|
||||
{
|
||||
DEBUG_FATAL(!source, ("source array is NULL"));
|
||||
DEBUG_FATAL(!result, ("result array is NULL"));
|
||||
DEBUG_FATAL(source == result, ("source and result array can not be the same"));
|
||||
|
||||
NOT_NULL(source);
|
||||
NOT_NULL(result);
|
||||
|
||||
for ( ; count; --count, ++source, ++result)
|
||||
{
|
||||
const real x = source->x;
|
||||
const real y = source->y;
|
||||
const real z = source->z;
|
||||
result->x = matrix[0][0] * x + matrix[0][1] * y + matrix[0][2] * z;
|
||||
result->y = matrix[1][0] * x + matrix[1][1] * y + matrix[1][2] * z;
|
||||
result->z = matrix[2][0] * x + matrix[2][1] * y + matrix[2][2] * z;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Transform an array of vectors from the matrix's current frame to the parent frame.
|
||||
*
|
||||
* Rotation and translation is most useful for vectors that are position, such as
|
||||
* vertex data.
|
||||
*
|
||||
* The source and result arrays may be the same array.
|
||||
*
|
||||
* @param source Source array of vectors to transform
|
||||
* @param result Array to store the result of the transforms
|
||||
* @param count Number of vertices to transform
|
||||
* @see Transform::rotate_l2p(), Transform::rotateTranslate_p2l()
|
||||
*/
|
||||
|
||||
void Transform::rotateTranslate_l2p(const Vector *source, Vector *result, int count) const
|
||||
{
|
||||
DEBUG_FATAL(!source, ("source array is NULL"));
|
||||
DEBUG_FATAL(!result, ("result array is NULL"));
|
||||
|
||||
NOT_NULL(source);
|
||||
NOT_NULL(result);
|
||||
|
||||
for ( ; count; --count, ++source, ++result)
|
||||
{
|
||||
const real x = source->x;
|
||||
const real y = source->y;
|
||||
const real z = source->z;
|
||||
|
||||
result->x = matrix[0][0] * x + matrix[0][1] * y + matrix[0][2] * z + matrix[0][3];
|
||||
result->y = matrix[1][0] * x + matrix[1][1] * y + matrix[1][2] * z + matrix[1][3];
|
||||
result->z = matrix[2][0] * x + matrix[2][1] * y + matrix[2][2] * z + matrix[2][3];
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Rotate an array of vectors from the parent's space to the local transform space.
|
||||
*
|
||||
* Pure rotation is most useful for vectors that are orientational, such as
|
||||
* normals.
|
||||
*
|
||||
* The source and result arrays may be the same array.
|
||||
*
|
||||
* @param source Source array of vectors to transform
|
||||
* @param result Array to store the result of the transforms
|
||||
* @param count Number of vertices to transform
|
||||
* @see Transform::rotateTranslate_p2l(), Transform::rotate_l2p()
|
||||
*/
|
||||
|
||||
void Transform::rotate_p2l(const Vector *source, Vector *result, int count) const
|
||||
{
|
||||
DEBUG_FATAL(!source, ("source array is NULL"));
|
||||
DEBUG_FATAL(!result, ("result array is NULL"));
|
||||
|
||||
NOT_NULL(source);
|
||||
NOT_NULL(result);
|
||||
|
||||
for ( ; count; --count, ++source, ++result)
|
||||
{
|
||||
const real x = source->x;
|
||||
const real y = source->y;
|
||||
const real z = source->z;
|
||||
|
||||
result->x = matrix[0][0] * x + matrix[1][0] * y + matrix[2][0] * z;
|
||||
result->y = matrix[0][1] * x + matrix[1][1] * y + matrix[2][1] * z;
|
||||
result->z = matrix[0][2] * x + matrix[1][2] * y + matrix[2][2] * z;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Transform an array of vectors from the parent spave to the local transform space.
|
||||
*
|
||||
* Rotation and translation is most useful for vectors that are position, such as
|
||||
* vertex data.
|
||||
*
|
||||
* The source and result arrays may be the same array.
|
||||
*
|
||||
* @param source Source array of vectors to transform
|
||||
* @param result Array to store the result of the transforms
|
||||
* @param count Number of vertices to transform
|
||||
* @see Transform::rotate_p2l(), Transform::rotateTranslate_l2p()
|
||||
*/
|
||||
|
||||
void Transform::rotateTranslate_p2l(const Vector *source, Vector *result, int count) const
|
||||
{
|
||||
DEBUG_FATAL(!source, ("source array is NULL"));
|
||||
DEBUG_FATAL(!result, ("result array is NULL"));
|
||||
|
||||
NOT_NULL(source);
|
||||
NOT_NULL(result);
|
||||
|
||||
for ( ; count; --count, ++source, ++result)
|
||||
{
|
||||
const real x = source->x - matrix[0][3];
|
||||
const real y = source->y - matrix[1][3];
|
||||
const real z = source->z - matrix[2][3];
|
||||
|
||||
result->x = matrix[0][0] * x + matrix[1][0] * y + matrix[2][0] * z;
|
||||
result->y = matrix[0][1] * x + matrix[1][1] * y + matrix[2][1] * z;
|
||||
result->z = matrix[0][2] * x + matrix[1][2] * y + matrix[2][2] * z;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const Transform Transform::rotateTranslate_l2p(const Transform &t) const
|
||||
{
|
||||
const Vector i = rotate_l2p(t.getLocalFrameI_p());
|
||||
const Vector j = rotate_l2p(t.getLocalFrameJ_p());
|
||||
const Vector k = rotate_l2p(t.getLocalFrameK_p());
|
||||
const Vector p = rotateTranslate_l2p(t.getPosition_p());
|
||||
|
||||
Transform tmp;
|
||||
tmp.setLocalFrameIJK_p(i, j, k);
|
||||
tmp.setPosition_p(p);
|
||||
tmp.reorthonormalize();
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const Transform Transform::rotateTranslate_p2l(const Transform &t) const
|
||||
{
|
||||
const Vector i = rotate_p2l(t.getLocalFrameI_p());
|
||||
const Vector j = rotate_p2l(t.getLocalFrameJ_p());
|
||||
const Vector k = rotate_p2l(t.getLocalFrameK_p());
|
||||
const Vector p = rotateTranslate_p2l(t.getPosition_p());
|
||||
|
||||
Transform tmp;
|
||||
tmp.setLocalFrameIJK_p(i, j, k);
|
||||
tmp.setPosition_p(p);
|
||||
tmp.reorthonormalize();
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool Transform::operator== (const Transform& rhs) const
|
||||
{
|
||||
return (memcmp (&rhs, this, sizeof(Transform) ) == 0);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool Transform::operator!= (const Transform& rhs) const
|
||||
{
|
||||
return !operator== (rhs);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
bool Transform::approximates(const Transform &rhs, float rotDelta, float posDelta) const
|
||||
{
|
||||
rotDelta = 1-rotDelta;
|
||||
posDelta *= posDelta;
|
||||
|
||||
float dot[3];
|
||||
int i;
|
||||
for (i=0; i<3; ++i)
|
||||
{
|
||||
dot[i] = matrix[0][i]*rhs.matrix[0][i] + matrix[1][i]*rhs.matrix[1][i] + matrix[2][i]*rhs.matrix[2][i];
|
||||
}
|
||||
|
||||
float dx = matrix[0][3]-rhs.matrix[0][3];
|
||||
float dy = matrix[1][3]-rhs.matrix[1][3];
|
||||
float dz = matrix[2][3]-rhs.matrix[2][3];
|
||||
|
||||
for (i=0; i<3; ++i)
|
||||
{
|
||||
if (dot[i] < rotDelta)
|
||||
return false;
|
||||
}
|
||||
|
||||
return dx*dx+dy*dy+dz*dz <= posDelta;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Set this Transform to a matrix that does nothing but scale
|
||||
* objects by the specified amount when computing from local to
|
||||
* parent space.
|
||||
*
|
||||
* @param scale the scale factor applied to x, y, z when transforming from local to parent space.
|
||||
*/
|
||||
|
||||
void Transform::setToScale(const Vector &scaleFactor)
|
||||
{
|
||||
matrix[0][0] = scaleFactor.x;
|
||||
matrix[0][1] = 0.0f;
|
||||
matrix[0][2] = 0.0f;
|
||||
matrix[0][3] = 0.0f;
|
||||
|
||||
matrix[1][0] = 0.0f;
|
||||
matrix[1][1] = scaleFactor.y;
|
||||
matrix[1][2] = 0.0f;
|
||||
matrix[1][3] = 0.0f;
|
||||
|
||||
matrix[2][0] = 0.0f;
|
||||
matrix[2][1] = 0.0f;
|
||||
matrix[2][2] = scaleFactor.z;
|
||||
matrix[2][3] = 0.0f;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Transform::ypr_l(real const y, real const p, real const r)
|
||||
{
|
||||
real const cy = cos(y);
|
||||
real const sy = sin(y);
|
||||
real const cp = cos(p);
|
||||
real const sp = sin(p);
|
||||
real const cr = cos(r);
|
||||
real const sr = sin(r);
|
||||
|
||||
matrix[0][0] = sp * sr * sy + cr * cy;
|
||||
matrix[0][1] = cr * sp * sy - cy * sr;
|
||||
matrix[0][2] = cp * sy;
|
||||
|
||||
matrix[1][0] = cp * sr;
|
||||
matrix[1][1] = cp * cr;
|
||||
matrix[1][2] = -sp;
|
||||
|
||||
matrix[2][0] = cy * sp * sr - cr * sy;
|
||||
matrix[2][1] = cr * cy * sp + sr * sy;
|
||||
matrix[2][2] = cp * cy;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
namespace
|
||||
{
|
||||
class ValidateBad
|
||||
{
|
||||
public:
|
||||
ValidateBad();
|
||||
~ValidateBad();
|
||||
void checked();
|
||||
private:
|
||||
int m_checked;
|
||||
};
|
||||
}
|
||||
|
||||
ValidateBad::ValidateBad()
|
||||
: m_checked(0)
|
||||
{
|
||||
}
|
||||
|
||||
ValidateBad::~ValidateBad()
|
||||
{
|
||||
REPORT_LOG(m_checked != 0, ("%d transforms checked", m_checked));
|
||||
}
|
||||
|
||||
void ValidateBad::checked()
|
||||
{
|
||||
++m_checked;
|
||||
}
|
||||
|
||||
static float magnitudeThreshold = 0.0001f;
|
||||
static float dotThreshold = cos(convertDegreesToRadians(0.05f));
|
||||
|
||||
static bool validate(bool allowFail, Vector const & a, Vector const & b)
|
||||
{
|
||||
const float magnitude = a.magnitude();
|
||||
if (!WithinEpsilonInclusive(1.0f, magnitude, magnitudeThreshold))
|
||||
{
|
||||
FATAL(!allowFail, ("Transform magnitude %0.12f", magnitude));
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector a2 = a;
|
||||
|
||||
IGNORE_RETURN( a2.normalize() );
|
||||
|
||||
const float dot = a2.dot(b);
|
||||
if (dot < dotThreshold)
|
||||
{
|
||||
FATAL(!allowFail, ("Transform angle off %0.12f", dot));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Transform::isNaN() const
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
for (int j = 0; j < 4; ++j)
|
||||
{
|
||||
#ifdef WIN32
|
||||
if(_isnan( static_cast<double>(matrix[i][j])))
|
||||
{
|
||||
DEBUG_FATAL(true, ("nan"));
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
if(isnan(matrix[i][j]))
|
||||
{
|
||||
DEBUG_FATAL(true, ("nan"));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Transform::realValidate(bool allowFail) const
|
||||
{
|
||||
static ValidateBad vb;
|
||||
vb.checked();
|
||||
|
||||
IGNORE_RETURN(isNaN());
|
||||
|
||||
Transform t = *this;
|
||||
t.reorthonormalize();
|
||||
t.reorthonormalize();
|
||||
t.reorthonormalize();
|
||||
|
||||
if (!::validate(allowFail, getLocalFrameI_p(), t.getLocalFrameI_p()))
|
||||
return false;
|
||||
if (!::validate(allowFail, getLocalFrameJ_p(), t.getLocalFrameJ_p()))
|
||||
return false;
|
||||
if (!::validate(allowFail, getLocalFrameK_p(), t.getLocalFrameK_p()))
|
||||
return false;
|
||||
|
||||
Quaternion q(*this);
|
||||
Transform u(IF_none);
|
||||
q.getTransform(&u);
|
||||
|
||||
if (!::validate(allowFail, u.getLocalFrameI_p(), t.getLocalFrameI_p()))
|
||||
return false;
|
||||
if (!::validate(allowFail, u.getLocalFrameJ_p(), t.getLocalFrameJ_p()))
|
||||
return false;
|
||||
if (!::validate(allowFail, u.getLocalFrameK_p(), t.getLocalFrameK_p()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -0,0 +1,615 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Transform.h
|
||||
// Portions copyright 1998 Bootprint Entertainment
|
||||
// Portions copyright 2000-2001 Sony Online Entertainment Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef INCLUDED_Transform_H
|
||||
#define INCLUDED_Transform_H
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#include "sharedMath/Vector.h"
|
||||
|
||||
// ======================================================================
|
||||
|
||||
namespace DPVS
|
||||
{
|
||||
class Matrix4x4;
|
||||
}
|
||||
|
||||
class Transform
|
||||
{
|
||||
friend class Direct3d8;
|
||||
friend class Direct3d9;
|
||||
friend class Iff;
|
||||
friend class MayaUtility;
|
||||
friend class OpenGL;
|
||||
friend class Quaternion;
|
||||
friend class SseMath;
|
||||
friend class RenderWorld;
|
||||
|
||||
public:
|
||||
|
||||
enum InitializeFlag
|
||||
{
|
||||
IF_none
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
static const Transform identity;
|
||||
|
||||
public:
|
||||
|
||||
static void install();
|
||||
|
||||
public:
|
||||
|
||||
typedef real matrix_t[3][4];
|
||||
|
||||
Transform(void);
|
||||
explicit Transform(InitializeFlag noInitialization);
|
||||
|
||||
void debugPrint(const char *header) const;
|
||||
|
||||
void reorthonormalize(void);
|
||||
void DLLEXPORT multiply(const Transform &lhs, const Transform &rhs);
|
||||
void invert(const Transform &transform);
|
||||
|
||||
void move_l(const Vector &vec);
|
||||
void move_p(const Vector &vec);
|
||||
|
||||
void yaw_l(real radians);
|
||||
void pitch_l(real radians);
|
||||
void roll_l(real radians);
|
||||
|
||||
// set ypr of the matrix.
|
||||
void ypr_l(real y, real p, real r);
|
||||
void ypr_l(Vector const & ypr);
|
||||
|
||||
void resetRotate_l2p(void);
|
||||
void resetRotateTranslate_l2p(void);
|
||||
|
||||
const Vector getPosition_p(void) const;
|
||||
void setPosition_p(const Vector &vec);
|
||||
void setPosition_p(real x, real y, real z);
|
||||
|
||||
const Vector getLocalFrameI_p(void) const;
|
||||
const Vector getLocalFrameJ_p(void) const;
|
||||
const Vector getLocalFrameK_p(void) const;
|
||||
void setLocalFrameIJK_p(const Vector &i, const Vector &j, const Vector &k);
|
||||
void setLocalFrameKJ_p(const Vector &k, const Vector &j);
|
||||
|
||||
const Vector getParentFrameI_l(void) const;
|
||||
const Vector getParentFrameJ_l(void) const;
|
||||
const Vector getParentFrameK_l(void) const;
|
||||
|
||||
const Vector rotate_l2p(const Vector &vec) const;
|
||||
const Vector rotateTranslate_l2p(const Vector &vec) const;
|
||||
const Vector rotate_p2l(const Vector &vec) const;
|
||||
const Vector rotateTranslate_p2l(const Vector &vec) const;
|
||||
|
||||
const Transform rotateTranslate_l2p(const Transform &t) const;
|
||||
const Transform rotateTranslate_p2l(const Transform &t) const;
|
||||
|
||||
void rotate_l2p(const Vector *source, Vector *result, int count) const;
|
||||
void rotateTranslate_l2p(const Vector *source, Vector *result, int count) const;
|
||||
void rotate_p2l(const Vector *source, Vector *result, int count) const;
|
||||
void rotateTranslate_p2l(const Vector *source, Vector *result, int count) const;
|
||||
|
||||
bool operator== (const Transform& rhs) const;
|
||||
bool operator!= (const Transform& rhs) const;
|
||||
bool approximates(const Transform &rhs, float rotDelta=0.001f, float posEpsilon=0.001f) const;
|
||||
|
||||
bool validate(bool allowFail=false) const;
|
||||
bool isNaN() const;
|
||||
|
||||
bool isYawOnly(void) const;
|
||||
bool isTranslateOnly(void) const;
|
||||
|
||||
void setToScale(const Vector &scaleFactor);
|
||||
void scale(float uniformScaleFactor);
|
||||
void scalePosition_p(float uniformScaleFactor);
|
||||
|
||||
const matrix_t &getMatrix() const { return matrix; }
|
||||
|
||||
private:
|
||||
|
||||
bool realValidate(bool allowFail) const;
|
||||
|
||||
private:
|
||||
|
||||
matrix_t matrix;
|
||||
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
// Turn this Transform into the identity transform
|
||||
//
|
||||
// Remarks:
|
||||
//
|
||||
// The identity Transform consists of a matrix of all 0 values with the exception of
|
||||
// the diagonal, which is all 1 values. This matrix will result in no change when
|
||||
// multiplied against other matrices or transforming vectors.
|
||||
|
||||
inline void Transform::resetRotateTranslate_l2p(void)
|
||||
{
|
||||
// make the diagonal 1's to form the identity matrix
|
||||
matrix[0][0] = CONST_REAL(1);
|
||||
matrix[0][1] = CONST_REAL(0);
|
||||
matrix[0][2] = CONST_REAL(0);
|
||||
matrix[0][3] = CONST_REAL(0);
|
||||
|
||||
matrix[1][0] = CONST_REAL(0);
|
||||
matrix[1][1] = CONST_REAL(1);
|
||||
matrix[1][2] = CONST_REAL(0);
|
||||
matrix[1][3] = CONST_REAL(0);
|
||||
|
||||
matrix[2][0] = CONST_REAL(0);
|
||||
matrix[2][1] = CONST_REAL(0);
|
||||
matrix[2][2] = CONST_REAL(1);
|
||||
matrix[2][3] = CONST_REAL(0);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Set the orientation to the identity orientation.
|
||||
*
|
||||
* This routine does NOT affect position
|
||||
*/
|
||||
|
||||
inline void Transform::resetRotate_l2p(void)
|
||||
{
|
||||
matrix[0][0] = CONST_REAL(1);
|
||||
matrix[0][1] = CONST_REAL(0);
|
||||
matrix[0][2] = CONST_REAL(0);
|
||||
|
||||
matrix[1][0] = CONST_REAL(0);
|
||||
matrix[1][1] = CONST_REAL(1);
|
||||
matrix[1][2] = CONST_REAL(0);
|
||||
|
||||
matrix[2][0] = CONST_REAL(0);
|
||||
matrix[2][1] = CONST_REAL(0);
|
||||
matrix[2][2] = CONST_REAL(1);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Construct a Transform.
|
||||
*
|
||||
* The transform will be initialized to the identity matrix.
|
||||
*
|
||||
* @see Transform::makeIdentity()
|
||||
*/
|
||||
|
||||
inline Transform::Transform(void)
|
||||
{
|
||||
resetRotateTranslate_l2p();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Construct a Transform without initialization.
|
||||
*
|
||||
* The transform matrix will not be initialized. This
|
||||
* member is intended for use only when efficiency is
|
||||
* a premium.
|
||||
*
|
||||
* @see Transform::Transform()
|
||||
*/
|
||||
|
||||
inline Transform::Transform(InitializeFlag noInitialization)
|
||||
{
|
||||
UNREF(noInitialization);
|
||||
} //lint !e1401 // warning, member 'matrix' not initialized // that's right, caller beware
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Move the transform in it's parent space.
|
||||
*
|
||||
* This routine moves the transform in it's parent space, or the world space if
|
||||
* the transform has no parent. Therefore, moving along the Z axis will move the
|
||||
* transform forward along the Z-axis of it's parent space, not forward in the
|
||||
* direction in which it is pointed.
|
||||
*
|
||||
* @param vec Displacement to move in parent space
|
||||
* @see Transform::move_l()
|
||||
*/
|
||||
|
||||
inline void Transform::move_p(const Vector &vec)
|
||||
{
|
||||
matrix[0][3] += vec.x;
|
||||
matrix[1][3] += vec.y;
|
||||
matrix[2][3] += vec.z;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Get the positional offset of this transform.
|
||||
*
|
||||
* This routine returns a temporary.
|
||||
*
|
||||
* The position returned is in parent space, which is world space if the
|
||||
* Transform has no parent.
|
||||
*
|
||||
* @return The positional offest of this transform in parent space.
|
||||
*/
|
||||
|
||||
inline const Vector Transform::getPosition_p(void) const
|
||||
{
|
||||
return Vector(matrix[0][3], matrix[1][3], matrix[2][3]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Set the positional offset of this transform.
|
||||
*
|
||||
* The position is specified in parent space, which is world space if the
|
||||
* Transform has no parent.
|
||||
*
|
||||
* @param vec New translation for this transform
|
||||
*/
|
||||
|
||||
inline void Transform::setPosition_p(const Vector &vec)
|
||||
{
|
||||
matrix[0][3] = vec.x;
|
||||
matrix[1][3] = vec.y;
|
||||
matrix[2][3] = vec.z;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Set the positional offset of this transform.
|
||||
*
|
||||
* The position is specified in parent space, which is world space if the
|
||||
* Transform has no parent.
|
||||
*
|
||||
* @param x New X translation for this transform
|
||||
* @param y New Y translation for this transform
|
||||
* @param z New Z translation for this transform
|
||||
*/
|
||||
|
||||
inline void Transform::setPosition_p(real x, real y, real z)
|
||||
{
|
||||
matrix[0][3] = x;
|
||||
matrix[1][3] = y;
|
||||
matrix[2][3] = z;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Set the transform matrix from the I, J, and K vectors.
|
||||
*
|
||||
* This routine assumes that I, J, and K are a left-handed orthonormal basis.
|
||||
* If they are not, the reorthonormalize() routine must be called after this routine.
|
||||
*
|
||||
* @param i Unit vector along the X axis
|
||||
* @param j Unit vector along the Y axis
|
||||
* @param k Unit vector along the Z axis
|
||||
*/
|
||||
|
||||
inline void Transform::setLocalFrameIJK_p(const Vector &i, const Vector &j, const Vector &k)
|
||||
{
|
||||
matrix[0][0] = i.x;
|
||||
matrix[1][0] = i.y;
|
||||
matrix[2][0] = i.z;
|
||||
|
||||
matrix[0][1] = j.x;
|
||||
matrix[1][1] = j.y;
|
||||
matrix[2][1] = j.z;
|
||||
|
||||
matrix[0][2] = k.x;
|
||||
matrix[1][2] = k.y;
|
||||
matrix[2][2] = k.z;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Set the transform matrix from K and J vectors.
|
||||
*
|
||||
* This routine assumes that K and J are part of a left-handed orthonormal basis.
|
||||
* If they are not, the reorthonormalize() routine must be called after this routine.
|
||||
*
|
||||
* @param k Unit vector along the Z axis
|
||||
* @param j Unit vector along the Y axis
|
||||
*/
|
||||
|
||||
inline void Transform::setLocalFrameKJ_p(const Vector &k, const Vector &j)
|
||||
{
|
||||
Vector i = j.cross(k);
|
||||
setLocalFrameIJK_p(i, j, k);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Get the parent-space vector pointing along the X axis of this frame of reference.
|
||||
*
|
||||
* This routine returns a temporary.
|
||||
*
|
||||
* The vector returned is in parent space, which is world space if the
|
||||
* Transform has no parent.
|
||||
*
|
||||
* @return The vector pointing along the X axis of the frame in parent space
|
||||
*/
|
||||
|
||||
inline const Vector Transform::getLocalFrameI_p(void) const
|
||||
{
|
||||
return Vector(matrix[0][0], matrix[1][0], matrix[2][0]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Get the parent-space vector pointing along the Y axis of this frame of reference.
|
||||
*
|
||||
* This routine returns a temporary.
|
||||
*
|
||||
* The vector returned is in parent space, which is world space if the
|
||||
* Transform has no parent.
|
||||
*
|
||||
* @return The vector pointing along the Y axis of the frame in parent space
|
||||
*/
|
||||
|
||||
inline const Vector Transform::getLocalFrameJ_p(void) const
|
||||
{
|
||||
return Vector(matrix[0][1], matrix[1][1], matrix[2][1]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Get the parent-space vector pointing along the Z axis of this frame of reference.
|
||||
*
|
||||
* This routine returns a temporary.
|
||||
*
|
||||
* The position returned is in parent space, which is world space if the
|
||||
* Transform has no parent.
|
||||
*
|
||||
* @return The vector pointing along the Z axis of the frame in parent space
|
||||
*/
|
||||
|
||||
inline const Vector Transform::getLocalFrameK_p(void) const
|
||||
{
|
||||
return Vector(matrix[0][2], matrix[1][2], matrix[2][2]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Get the transform-space vector pointing along the X axis of the parent of reference.
|
||||
*
|
||||
* This routine returns a temporary.
|
||||
*
|
||||
* The vector returned is in local space.
|
||||
*
|
||||
* @return The vector pointing along the X axis of the parent's frame in local space
|
||||
*/
|
||||
|
||||
inline const Vector Transform::getParentFrameI_l(void) const
|
||||
{
|
||||
return Vector(matrix[0][0], matrix[0][1], matrix[0][2]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Get the transform-space vector pointing along the Y axis of the parent of reference.
|
||||
*
|
||||
* This routine returns a temporary.
|
||||
*
|
||||
* The vector returned is in local space.
|
||||
*
|
||||
* @return The vector pointing along the Y axis of the parent's frame in local space
|
||||
*/
|
||||
|
||||
inline const Vector Transform::getParentFrameJ_l(void) const
|
||||
{
|
||||
return Vector(matrix[1][0], matrix[1][1], matrix[1][2]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Get the transform-space vector pointing along the Z axis of the parent of reference.
|
||||
*
|
||||
* This routine returns a temporary.
|
||||
*
|
||||
* The vector returned is in local space.
|
||||
*
|
||||
* @return The vector pointing along the Z axis of the parent's frame in local space
|
||||
*/
|
||||
|
||||
inline const Vector Transform::getParentFrameK_l(void) const
|
||||
{
|
||||
return Vector(matrix[2][0], matrix[2][1], matrix[2][2]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Rotate vector from the matrix's current frame to the parent frame.
|
||||
*
|
||||
* This routine returns a temporary.
|
||||
*
|
||||
* Pure rotation is most useful for vectors that are orientational, such as
|
||||
* normals.
|
||||
*
|
||||
* @param vec Vector to rotate
|
||||
* @return The vector in parent space
|
||||
* @see Transform::rotateTranslate_l2p(), Transform::rotate_p2l()
|
||||
*/
|
||||
|
||||
inline const Vector Transform::rotate_l2p(const Vector &vec) const
|
||||
{
|
||||
return Vector(
|
||||
matrix[0][0] * vec.x + matrix[0][1] * vec.y + matrix[0][2] * vec.z,
|
||||
matrix[1][0] * vec.x + matrix[1][1] * vec.y + matrix[1][2] * vec.z,
|
||||
matrix[2][0] * vec.x + matrix[2][1] * vec.y + matrix[2][2] * vec.z);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Transform the vector from the matrix's current frame to the parent frame.
|
||||
*
|
||||
* This routine returns a temporary.
|
||||
*
|
||||
* Rotation and translation is most useful for vectors that are position, such as
|
||||
* vertex data.
|
||||
*
|
||||
* @param vec Vector to rotate and translate
|
||||
* @return The vector in parent space
|
||||
* @see Transform::rotate_l2p(), Transform::rotateTranslate_p2l()
|
||||
*/
|
||||
|
||||
inline const Vector Transform::rotateTranslate_l2p(const Vector &vec) const
|
||||
{
|
||||
return Vector (
|
||||
matrix[0][0] * vec.x + matrix[0][1] * vec.y + matrix[0][2] * vec.z + matrix[0][3],
|
||||
matrix[1][0] * vec.x + matrix[1][1] * vec.y + matrix[1][2] * vec.z + matrix[1][3],
|
||||
matrix[2][0] * vec.x + matrix[2][1] * vec.y + matrix[2][2] * vec.z + matrix[2][3]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Rotate vector from the parent's space to the local transform space.
|
||||
*
|
||||
* This routine returns a temporary.
|
||||
*
|
||||
* Pure rotation is most useful for vectors that are orientational, such as
|
||||
* normals.
|
||||
*
|
||||
* @param vec Vector to rotate
|
||||
* @return The vector in local space
|
||||
* @see Transform::rotateTranslate_p2l(), Transform::rotate_l2p()
|
||||
*/
|
||||
|
||||
inline const Vector Transform::rotate_p2l(const Vector &vec) const
|
||||
{
|
||||
return Vector (
|
||||
matrix[0][0] * vec.x + matrix[1][0] * vec.y + matrix[2][0] * vec.z,
|
||||
matrix[0][1] * vec.x + matrix[1][1] * vec.y + matrix[2][1] * vec.z,
|
||||
matrix[0][2] * vec.x + matrix[1][2] * vec.y + matrix[2][2] * vec.z);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Transform the vector from the parent spave to the local transform space.
|
||||
*
|
||||
* This routine returns a temporary.
|
||||
*
|
||||
* Rotation and translation is most useful for vectors that are position, such as
|
||||
* vertex data.
|
||||
*
|
||||
* @return The vector in local space
|
||||
* @see Transform::rotate_p2l(), Transform::rotateTranslate_l2p()
|
||||
*/
|
||||
|
||||
inline const Vector Transform::rotateTranslate_p2l(const Vector &vec) const
|
||||
{
|
||||
const real x = vec.x - matrix[0][3];
|
||||
const real y = vec.y - matrix[1][3];
|
||||
const real z = vec.z - matrix[2][3];
|
||||
|
||||
return Vector(
|
||||
matrix[0][0] * x + matrix[1][0] * y + matrix[2][0] * z,
|
||||
matrix[0][1] * x + matrix[1][1] * y + matrix[2][1] * z,
|
||||
matrix[0][2] * x + matrix[1][2] * y + matrix[2][2] * z);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Move the transform in it's own local space.
|
||||
*
|
||||
* This routine moves the transform according to its current frame of reference.
|
||||
* Therefore, moving along the Z axis will move the transform forward in the direction
|
||||
* in which it is pointed.
|
||||
*
|
||||
* @param vec Vector to rotate and translate
|
||||
* @see Transform::moveInParentSpace()
|
||||
*/
|
||||
|
||||
inline void Transform::move_l(const Vector &vec)
|
||||
{
|
||||
move_p(rotate_l2p(vec));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Returns true if the rotation component of a transform is yaw-only
|
||||
// (no X- or Z-axis rotation)
|
||||
|
||||
// This test is very simple when we're guaranteed that our axes are orthonormal
|
||||
|
||||
inline bool Transform::isYawOnly(void) const
|
||||
{
|
||||
return abs(matrix[1][1] - 1.0f) < 0.00001f;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Returns true if the transform does no rotation.
|
||||
|
||||
// This test is very simple when we're guaranteed that our axes are orthonormal
|
||||
|
||||
inline bool Transform::isTranslateOnly(void) const
|
||||
{
|
||||
if(abs(matrix[0][0] - 1.0f) > 0.00001f) return false;
|
||||
if(abs(matrix[1][1] - 1.0f) > 0.00001f) return false;
|
||||
if(abs(matrix[2][2] - 1.0f) > 0.00001f) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline bool Transform::validate(bool allowFail) const
|
||||
{
|
||||
UNREF(allowFail);
|
||||
// return realValidate(allowFail);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Set the uniform scale factor applied to the transform's rotation
|
||||
* matrix.
|
||||
*
|
||||
* This function does not manipulate the position information within
|
||||
* the parent space.
|
||||
*
|
||||
* @param uniformScaleFactor the scale factor to apply to the diagonal
|
||||
* of the rotation matrix.
|
||||
*
|
||||
* @see Transform::scalePosition_p().
|
||||
*/
|
||||
|
||||
inline void Transform::scale(float uniformScaleFactor)
|
||||
{
|
||||
matrix[0][0] *= uniformScaleFactor;
|
||||
matrix[1][1] *= uniformScaleFactor;
|
||||
matrix[2][2] *= uniformScaleFactor;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Scale the parent-space positioning information for the Transform.
|
||||
*
|
||||
* @param uniformScaleFactor the scale factor to apply to the position
|
||||
* of the Transform in parent space.
|
||||
*/
|
||||
|
||||
inline void Transform::scalePosition_p(float uniformScaleFactor)
|
||||
{
|
||||
matrix[0][3] *= uniformScaleFactor;
|
||||
matrix[1][3] *= uniformScaleFactor;
|
||||
matrix[2][3] *= uniformScaleFactor;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline void Transform::ypr_l(Vector const & ypr)
|
||||
{
|
||||
ypr_l(ypr.x, ypr.y, ypr.z);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user