From a4f2c06f7757fc355751a14b5a720f034b6a13b7 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Tue, 14 Jan 2014 02:05:25 -0700 Subject: [PATCH] Added sharedMath and sharedRandom libraries --- engine/shared/library/CMakeLists.txt | 2 + .../library/sharedDebug/src/CMakeLists.txt | 2 +- .../shared/library/sharedMath/CMakeLists.txt | 11 + .../include/public/sharedMath/AxialBox.h | 1 + .../include/public/sharedMath/Capsule.h | 1 + .../public/sharedMath/CatmullRomSpline.h | 1 + .../include/public/sharedMath/Circle.h | 2 + .../public/sharedMath/CompressedQuaternion.h | 1 + .../public/sharedMath/ConfigSharedMath.h | 1 + .../include/public/sharedMath/Cylinder.h | 1 + .../public/sharedMath/DebugShapeRenderer.h | 1 + .../public/sharedMath/FirstSharedMath.h | 1 + .../include/public/sharedMath/Hsv.h | 1 + .../public/sharedMath/IndexedTriangleList.h | 1 + .../include/public/sharedMath/Line2d.h | 1 + .../include/public/sharedMath/Line3d.h | 1 + .../include/public/sharedMath/MultiShape.h | 1 + .../include/public/sharedMath/MxCifQuadTree.h | 1 + .../public/sharedMath/MxCifQuadTreeBounds.h | 1 + .../include/public/sharedMath/OrientedBox.h | 1 + .../public/sharedMath/OrientedCircle.h | 1 + .../public/sharedMath/OrientedCylinder.h | 1 + .../include/public/sharedMath/PackedArgb.h | 1 + .../include/public/sharedMath/PackedRgb.h | 1 + .../include/public/sharedMath/PaletteArgb.h | 1 + .../public/sharedMath/PaletteArgbList.h | 1 + .../include/public/sharedMath/Plane.h | 1 + .../include/public/sharedMath/Plane3d.h | 2 + .../include/public/sharedMath/PolySolver.h | 1 + .../public/sharedMath/PositionVertexIndexer.h | 1 + .../include/public/sharedMath/Quadratic.h | 1 + .../include/public/sharedMath/Quaternion.h | 1 + .../include/public/sharedMath/Range.h | 1 + .../include/public/sharedMath/RangeLoop.h | 1 + .../include/public/sharedMath/Ray3d.h | 1 + .../include/public/sharedMath/Rectangle2d.h | 1 + .../include/public/sharedMath/Ribbon3d.h | 2 + .../include/public/sharedMath/Ring.h | 1 + .../include/public/sharedMath/Segment3d.h | 1 + .../public/sharedMath/SetupSharedMath.h | 1 + .../include/public/sharedMath/ShapeUtils.h | 1 + .../public/sharedMath/SpatialSubdivision.h | 1 + .../include/public/sharedMath/Sphere.h | 1 + .../include/public/sharedMath/SphereTree.h | 1 + .../public/sharedMath/SphereTreeNode.h | 1 + .../include/public/sharedMath/SseMath.h | 5 + .../include/public/sharedMath/Torus.h | 1 + .../include/public/sharedMath/Transform.h | 1 + .../include/public/sharedMath/Transform2d.h | 1 + .../include/public/sharedMath/Triangle2d.h | 1 + .../include/public/sharedMath/Triangle3d.h | 1 + .../include/public/sharedMath/Vector.h | 1 + .../include/public/sharedMath/Vector2d.h | 1 + .../include/public/sharedMath/VectorArgb.h | 1 + .../include/public/sharedMath/VectorRgba.h | 1 + .../include/public/sharedMath/Volume.h | 1 + .../include/public/sharedMath/WaveForm.h | 1 + .../include/public/sharedMath/WaveForm3D.h | 1 + .../include/public/sharedMath/YawedBox.h | 1 + .../library/sharedMath/src/CMakeLists.txt | 133 ++ .../src/shared/CatmullRomSpline.cpp | 42 + .../sharedMath/src/shared/CatmullRomSpline.h | 33 + .../src/shared/CompressedQuaternion.cpp | 637 +++++++ .../src/shared/CompressedQuaternion.h | 56 + .../src/shared/ConfigSharedMath.cpp | 42 + .../sharedMath/src/shared/ConfigSharedMath.h | 24 + .../sharedMath/src/shared/FirstSharedMath.h | 18 + .../src/shared/IndexedTriangleList.cpp | 398 ++++ .../src/shared/IndexedTriangleList.h | 89 + .../library/sharedMath/src/shared/Line2d.h | 156 ++ .../sharedMath/src/shared/MxCifQuadTree.cpp | 520 ++++++ .../sharedMath/src/shared/MxCifQuadTree.h | 163 ++ .../src/shared/MxCifQuadTreeBounds.cpp | 41 + .../src/shared/MxCifQuadTreeBounds.h | 141 ++ .../sharedMath/src/shared/PackedArgb.cpp | 64 + .../sharedMath/src/shared/PackedArgb.h | 278 +++ .../sharedMath/src/shared/PackedRgb.cpp | 75 + .../library/sharedMath/src/shared/PackedRgb.h | 87 + .../sharedMath/src/shared/PaletteArgb.cpp | 609 ++++++ .../sharedMath/src/shared/PaletteArgb.h | 163 ++ .../sharedMath/src/shared/PaletteArgbList.cpp | 242 +++ .../sharedMath/src/shared/PaletteArgbList.h | 63 + .../library/sharedMath/src/shared/Plane.cpp | 371 ++++ .../library/sharedMath/src/shared/Plane.h | 245 +++ .../sharedMath/src/shared/PolySolver.cpp | 319 ++++ .../sharedMath/src/shared/PolySolver.h | 26 + .../src/shared/PositionVertexIndexer.cpp | 146 ++ .../src/shared/PositionVertexIndexer.h | 53 + .../sharedMath/src/shared/Quaternion.cpp | 356 ++++ .../sharedMath/src/shared/Quaternion.h | 108 ++ .../sharedMath/src/shared/Rectangle2d.cpp | 98 + .../sharedMath/src/shared/Rectangle2d.h | 208 +++ .../sharedMath/src/shared/SetupSharedMath.cpp | 36 + .../sharedMath/src/shared/SetupSharedMath.h | 24 + .../src/shared/SpatialSubdivision.cpp | 41 + .../src/shared/SpatialSubdivision.h | 124 ++ .../library/sharedMath/src/shared/Sphere.cpp | 113 ++ .../library/sharedMath/src/shared/Sphere.h | 347 ++++ .../sharedMath/src/shared/SphereTree.h | 657 +++++++ .../sharedMath/src/shared/SphereTreeNode.h | 1652 +++++++++++++++++ .../sharedMath/src/shared/Transform.cpp | 889 +++++++++ .../library/sharedMath/src/shared/Transform.h | 615 ++++++ .../sharedMath/src/shared/Transform2d.cpp | 118 ++ .../sharedMath/src/shared/Transform2d.h | 171 ++ .../library/sharedMath/src/shared/Vector.cpp | 321 ++++ .../library/sharedMath/src/shared/Vector.h | 716 +++++++ .../library/sharedMath/src/shared/Vector2d.h | 310 ++++ .../sharedMath/src/shared/VectorArgb.cpp | 39 + .../sharedMath/src/shared/VectorArgb.h | 155 ++ .../sharedMath/src/shared/VectorRgba.cpp | 44 + .../sharedMath/src/shared/VectorRgba.h | 148 ++ .../library/sharedMath/src/shared/Volume.cpp | 289 +++ .../library/sharedMath/src/shared/Volume.h | 68 + .../sharedMath/src/shared/WaveForm.cpp | 1130 +++++++++++ .../library/sharedMath/src/shared/WaveForm.h | 218 +++ .../sharedMath/src/shared/WaveForm3D.cpp | 71 + .../sharedMath/src/shared/WaveForm3D.h | 67 + .../sharedMath/src/shared/core/AxialBox.cpp | 174 ++ .../sharedMath/src/shared/core/AxialBox.h | 180 ++ .../sharedMath/src/shared/core/Capsule.cpp | 11 + .../sharedMath/src/shared/core/Capsule.h | 174 ++ .../sharedMath/src/shared/core/Circle.cpp | 34 + .../sharedMath/src/shared/core/Circle.h | 92 + .../sharedMath/src/shared/core/Cylinder.cpp | 39 + .../sharedMath/src/shared/core/Cylinder.h | 160 ++ .../sharedMath/src/shared/core/Hsv.cpp | 80 + .../library/sharedMath/src/shared/core/Hsv.h | 33 + .../sharedMath/src/shared/core/Line3d.cpp | 9 + .../sharedMath/src/shared/core/Line3d.h | 70 + .../sharedMath/src/shared/core/MultiShape.cpp | 414 +++++ .../sharedMath/src/shared/core/MultiShape.h | 258 +++ .../src/shared/core/OrientedBox.cpp | 133 ++ .../sharedMath/src/shared/core/OrientedBox.h | 182 ++ .../src/shared/core/OrientedCircle.cpp | 28 + .../src/shared/core/OrientedCircle.h | 57 + .../src/shared/core/OrientedCylinder.cpp | 121 ++ .../src/shared/core/OrientedCylinder.h | 175 ++ .../sharedMath/src/shared/core/Plane3d.cpp | 17 + .../sharedMath/src/shared/core/Plane3d.h | 91 + .../sharedMath/src/shared/core/Quadratic.cpp | 68 + .../sharedMath/src/shared/core/Quadratic.h | 42 + .../sharedMath/src/shared/core/Range.cpp | 71 + .../sharedMath/src/shared/core/Range.h | 225 +++ .../sharedMath/src/shared/core/RangeLoop.cpp | 458 +++++ .../sharedMath/src/shared/core/RangeLoop.h | 120 ++ .../sharedMath/src/shared/core/Ray3d.cpp | 18 + .../sharedMath/src/shared/core/Ray3d.h | 61 + .../sharedMath/src/shared/core/Ribbon3d.cpp | 56 + .../sharedMath/src/shared/core/Ribbon3d.h | 72 + .../sharedMath/src/shared/core/Ring.cpp | 35 + .../library/sharedMath/src/shared/core/Ring.h | 78 + .../sharedMath/src/shared/core/Segment3d.cpp | 38 + .../sharedMath/src/shared/core/Segment3d.h | 99 + .../sharedMath/src/shared/core/ShapeUtils.cpp | 327 ++++ .../sharedMath/src/shared/core/ShapeUtils.h | 119 ++ .../sharedMath/src/shared/core/Torus.cpp | 42 + .../sharedMath/src/shared/core/Torus.h | 103 + .../sharedMath/src/shared/core/Triangle2d.cpp | 10 + .../sharedMath/src/shared/core/Triangle2d.h | 102 + .../sharedMath/src/shared/core/Triangle3d.cpp | 200 ++ .../sharedMath/src/shared/core/Triangle3d.h | 85 + .../sharedMath/src/shared/core/YawedBox.cpp | 102 + .../sharedMath/src/shared/core/YawedBox.h | 173 ++ .../src/shared/debug/DebugShapeRenderer.cpp | 152 ++ .../src/shared/debug/DebugShapeRenderer.h | 105 ++ .../sharedMath/src/win32/FirstSharedMath.cpp | 8 + .../library/sharedMath/src/win32/SseMath.cpp | 430 +++++ .../library/sharedMath/src/win32/SseMath.h | 58 + .../library/sharedRandom/CMakeLists.txt | 11 + .../public/sharedRandom/ConfigSharedRandom.h | 1 + .../public/sharedRandom/FastRandomGenerator.h | 1 + .../public/sharedRandom/FirstSharedRandom.h | 1 + .../include/public/sharedRandom/Random.h | 1 + .../public/sharedRandom/RandomGenerator.h | 1 + .../public/sharedRandom/SetupSharedRandom.h | 1 + .../library/sharedRandom/src/CMakeLists.txt | 36 + .../src/shared/ConfigSharedRandom.cpp | 42 + .../src/shared/ConfigSharedRandom.h | 24 + .../src/shared/FastRandomGenerator.h | 71 + .../src/shared/FirstSharedRandom.h | 19 + .../sharedRandom/src/shared/Random.cpp | 50 + .../library/sharedRandom/src/shared/Random.h | 190 ++ .../src/shared/RandomGenerator.cpp | 72 + .../sharedRandom/src/shared/RandomGenerator.h | 217 +++ .../src/shared/SetupSharedRandom.cpp | 25 + .../src/shared/SetupSharedRandom.h | 27 + .../src/win32/FirstSharedRandom.cpp | 8 + 187 files changed, 21231 insertions(+), 1 deletion(-) create mode 100644 engine/shared/library/sharedMath/CMakeLists.txt create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/AxialBox.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Capsule.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/CatmullRomSpline.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Circle.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/CompressedQuaternion.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/ConfigSharedMath.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Cylinder.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/DebugShapeRenderer.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/FirstSharedMath.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Hsv.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/IndexedTriangleList.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Line2d.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Line3d.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/MultiShape.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/MxCifQuadTree.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/MxCifQuadTreeBounds.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/OrientedBox.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/OrientedCircle.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/OrientedCylinder.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/PackedArgb.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/PackedRgb.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/PaletteArgb.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/PaletteArgbList.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Plane.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Plane3d.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/PolySolver.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/PositionVertexIndexer.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Quadratic.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Quaternion.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Range.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/RangeLoop.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Ray3d.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Rectangle2d.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Ribbon3d.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Ring.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Segment3d.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/SetupSharedMath.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/ShapeUtils.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/SpatialSubdivision.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Sphere.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/SphereTree.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/SphereTreeNode.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/SseMath.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Torus.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Transform.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Transform2d.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Triangle2d.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Triangle3d.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Vector.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Vector2d.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/VectorArgb.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/VectorRgba.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/Volume.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/WaveForm.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/WaveForm3D.h create mode 100644 engine/shared/library/sharedMath/include/public/sharedMath/YawedBox.h create mode 100644 engine/shared/library/sharedMath/src/CMakeLists.txt create mode 100644 engine/shared/library/sharedMath/src/shared/CatmullRomSpline.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/CatmullRomSpline.h create mode 100644 engine/shared/library/sharedMath/src/shared/CompressedQuaternion.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/CompressedQuaternion.h create mode 100644 engine/shared/library/sharedMath/src/shared/ConfigSharedMath.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/ConfigSharedMath.h create mode 100644 engine/shared/library/sharedMath/src/shared/FirstSharedMath.h create mode 100644 engine/shared/library/sharedMath/src/shared/IndexedTriangleList.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/IndexedTriangleList.h create mode 100644 engine/shared/library/sharedMath/src/shared/Line2d.h create mode 100644 engine/shared/library/sharedMath/src/shared/MxCifQuadTree.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/MxCifQuadTree.h create mode 100644 engine/shared/library/sharedMath/src/shared/MxCifQuadTreeBounds.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/MxCifQuadTreeBounds.h create mode 100644 engine/shared/library/sharedMath/src/shared/PackedArgb.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/PackedArgb.h create mode 100644 engine/shared/library/sharedMath/src/shared/PackedRgb.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/PackedRgb.h create mode 100644 engine/shared/library/sharedMath/src/shared/PaletteArgb.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/PaletteArgb.h create mode 100644 engine/shared/library/sharedMath/src/shared/PaletteArgbList.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/PaletteArgbList.h create mode 100644 engine/shared/library/sharedMath/src/shared/Plane.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/Plane.h create mode 100644 engine/shared/library/sharedMath/src/shared/PolySolver.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/PolySolver.h create mode 100644 engine/shared/library/sharedMath/src/shared/PositionVertexIndexer.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/PositionVertexIndexer.h create mode 100644 engine/shared/library/sharedMath/src/shared/Quaternion.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/Quaternion.h create mode 100644 engine/shared/library/sharedMath/src/shared/Rectangle2d.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/Rectangle2d.h create mode 100644 engine/shared/library/sharedMath/src/shared/SetupSharedMath.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/SetupSharedMath.h create mode 100644 engine/shared/library/sharedMath/src/shared/SpatialSubdivision.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/SpatialSubdivision.h create mode 100644 engine/shared/library/sharedMath/src/shared/Sphere.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/Sphere.h create mode 100644 engine/shared/library/sharedMath/src/shared/SphereTree.h create mode 100644 engine/shared/library/sharedMath/src/shared/SphereTreeNode.h create mode 100644 engine/shared/library/sharedMath/src/shared/Transform.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/Transform.h create mode 100644 engine/shared/library/sharedMath/src/shared/Transform2d.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/Transform2d.h create mode 100644 engine/shared/library/sharedMath/src/shared/Vector.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/Vector.h create mode 100644 engine/shared/library/sharedMath/src/shared/Vector2d.h create mode 100644 engine/shared/library/sharedMath/src/shared/VectorArgb.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/VectorArgb.h create mode 100644 engine/shared/library/sharedMath/src/shared/VectorRgba.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/VectorRgba.h create mode 100644 engine/shared/library/sharedMath/src/shared/Volume.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/Volume.h create mode 100644 engine/shared/library/sharedMath/src/shared/WaveForm.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/WaveForm.h create mode 100644 engine/shared/library/sharedMath/src/shared/WaveForm3D.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/WaveForm3D.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/AxialBox.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/AxialBox.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/Capsule.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/Capsule.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/Circle.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/Circle.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/Cylinder.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/Cylinder.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/Hsv.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/Hsv.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/Line3d.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/Line3d.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/MultiShape.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/MultiShape.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/OrientedBox.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/OrientedBox.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/OrientedCircle.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/OrientedCircle.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/OrientedCylinder.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/OrientedCylinder.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/Plane3d.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/Plane3d.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/Quadratic.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/Quadratic.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/Range.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/Range.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/RangeLoop.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/RangeLoop.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/Ray3d.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/Ray3d.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/Ribbon3d.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/Ribbon3d.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/Ring.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/Ring.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/Segment3d.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/Segment3d.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/ShapeUtils.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/ShapeUtils.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/Torus.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/Torus.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/Triangle2d.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/Triangle2d.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/Triangle3d.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/Triangle3d.h create mode 100644 engine/shared/library/sharedMath/src/shared/core/YawedBox.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/core/YawedBox.h create mode 100644 engine/shared/library/sharedMath/src/shared/debug/DebugShapeRenderer.cpp create mode 100644 engine/shared/library/sharedMath/src/shared/debug/DebugShapeRenderer.h create mode 100644 engine/shared/library/sharedMath/src/win32/FirstSharedMath.cpp create mode 100644 engine/shared/library/sharedMath/src/win32/SseMath.cpp create mode 100644 engine/shared/library/sharedMath/src/win32/SseMath.h create mode 100644 engine/shared/library/sharedRandom/CMakeLists.txt create mode 100644 engine/shared/library/sharedRandom/include/public/sharedRandom/ConfigSharedRandom.h create mode 100644 engine/shared/library/sharedRandom/include/public/sharedRandom/FastRandomGenerator.h create mode 100644 engine/shared/library/sharedRandom/include/public/sharedRandom/FirstSharedRandom.h create mode 100644 engine/shared/library/sharedRandom/include/public/sharedRandom/Random.h create mode 100644 engine/shared/library/sharedRandom/include/public/sharedRandom/RandomGenerator.h create mode 100644 engine/shared/library/sharedRandom/include/public/sharedRandom/SetupSharedRandom.h create mode 100644 engine/shared/library/sharedRandom/src/CMakeLists.txt create mode 100644 engine/shared/library/sharedRandom/src/shared/ConfigSharedRandom.cpp create mode 100644 engine/shared/library/sharedRandom/src/shared/ConfigSharedRandom.h create mode 100644 engine/shared/library/sharedRandom/src/shared/FastRandomGenerator.h create mode 100644 engine/shared/library/sharedRandom/src/shared/FirstSharedRandom.h create mode 100644 engine/shared/library/sharedRandom/src/shared/Random.cpp create mode 100644 engine/shared/library/sharedRandom/src/shared/Random.h create mode 100644 engine/shared/library/sharedRandom/src/shared/RandomGenerator.cpp create mode 100644 engine/shared/library/sharedRandom/src/shared/RandomGenerator.h create mode 100644 engine/shared/library/sharedRandom/src/shared/SetupSharedRandom.cpp create mode 100644 engine/shared/library/sharedRandom/src/shared/SetupSharedRandom.h create mode 100644 engine/shared/library/sharedRandom/src/win32/FirstSharedRandom.cpp diff --git a/engine/shared/library/CMakeLists.txt b/engine/shared/library/CMakeLists.txt index 2d6a7ff2..523f0e81 100644 --- a/engine/shared/library/CMakeLists.txt +++ b/engine/shared/library/CMakeLists.txt @@ -3,7 +3,9 @@ add_subdirectory(sharedDebug) add_subdirectory(sharedFile) add_subdirectory(sharedFoundation) add_subdirectory(sharedFoundationTypes) +add_subdirectory(sharedMath) add_subdirectory(sharedMemoryManager) add_subdirectory(sharedNetworkMessages) +add_subdirectory(sharedRandom) add_subdirectory(sharedSynchronization) add_subdirectory(sharedThread) diff --git a/engine/shared/library/sharedDebug/src/CMakeLists.txt b/engine/shared/library/sharedDebug/src/CMakeLists.txt index aa4f09d3..d26a2960 100644 --- a/engine/shared/library/sharedDebug/src/CMakeLists.txt +++ b/engine/shared/library/sharedDebug/src/CMakeLists.txt @@ -65,7 +65,7 @@ include_directories( ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundation/include/public ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundationTypes/include/public ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMemoryManager/include/public - ${SWG_ROOT_SOURCE_DIR}/external/3rd/library/vtune + ${SWG_EXTERNALS_SOURCE_DIR}/3rd/library/vtune ) add_library(sharedDebug STATIC diff --git a/engine/shared/library/sharedMath/CMakeLists.txt b/engine/shared/library/sharedMath/CMakeLists.txt new file mode 100644 index 00000000..5b89b384 --- /dev/null +++ b/engine/shared/library/sharedMath/CMakeLists.txt @@ -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) diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/AxialBox.h b/engine/shared/library/sharedMath/include/public/sharedMath/AxialBox.h new file mode 100644 index 00000000..01d99f8e --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/AxialBox.h @@ -0,0 +1 @@ +#include "../../src/shared/core/AxialBox.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Capsule.h b/engine/shared/library/sharedMath/include/public/sharedMath/Capsule.h new file mode 100644 index 00000000..eecc7a2e --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Capsule.h @@ -0,0 +1 @@ +#include "../../src/shared/core/Capsule.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/CatmullRomSpline.h b/engine/shared/library/sharedMath/include/public/sharedMath/CatmullRomSpline.h new file mode 100644 index 00000000..97aaf96a --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/CatmullRomSpline.h @@ -0,0 +1 @@ +#include "../../src/shared/CatmullRomSpline.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Circle.h b/engine/shared/library/sharedMath/include/public/sharedMath/Circle.h new file mode 100644 index 00000000..f10ea529 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Circle.h @@ -0,0 +1,2 @@ +#include "../../src/shared/core/Circle.h" + diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/CompressedQuaternion.h b/engine/shared/library/sharedMath/include/public/sharedMath/CompressedQuaternion.h new file mode 100644 index 00000000..e608ba3f --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/CompressedQuaternion.h @@ -0,0 +1 @@ +#include "../../src/shared/CompressedQuaternion.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/ConfigSharedMath.h b/engine/shared/library/sharedMath/include/public/sharedMath/ConfigSharedMath.h new file mode 100644 index 00000000..c163c8b3 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/ConfigSharedMath.h @@ -0,0 +1 @@ +#include "../../src/shared/ConfigSharedMath.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Cylinder.h b/engine/shared/library/sharedMath/include/public/sharedMath/Cylinder.h new file mode 100644 index 00000000..b6ef37df --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Cylinder.h @@ -0,0 +1 @@ +#include "../../src/shared/core/Cylinder.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/DebugShapeRenderer.h b/engine/shared/library/sharedMath/include/public/sharedMath/DebugShapeRenderer.h new file mode 100644 index 00000000..d840fb59 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/DebugShapeRenderer.h @@ -0,0 +1 @@ +#include "../../src/shared/debug/DebugShapeRenderer.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/FirstSharedMath.h b/engine/shared/library/sharedMath/include/public/sharedMath/FirstSharedMath.h new file mode 100644 index 00000000..7469d4a8 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/FirstSharedMath.h @@ -0,0 +1 @@ +#include "../../src/shared/FirstSharedMath.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Hsv.h b/engine/shared/library/sharedMath/include/public/sharedMath/Hsv.h new file mode 100644 index 00000000..b39e9f33 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Hsv.h @@ -0,0 +1 @@ +#include "../../src/shared/core/Hsv.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/IndexedTriangleList.h b/engine/shared/library/sharedMath/include/public/sharedMath/IndexedTriangleList.h new file mode 100644 index 00000000..7f6a7862 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/IndexedTriangleList.h @@ -0,0 +1 @@ +#include "../../src/shared/IndexedTriangleList.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Line2d.h b/engine/shared/library/sharedMath/include/public/sharedMath/Line2d.h new file mode 100644 index 00000000..56ad8b2c --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Line2d.h @@ -0,0 +1 @@ +#include "../../src/shared/Line2d.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Line3d.h b/engine/shared/library/sharedMath/include/public/sharedMath/Line3d.h new file mode 100644 index 00000000..ed64038d --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Line3d.h @@ -0,0 +1 @@ +#include "../../src/shared/core/Line3d.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/MultiShape.h b/engine/shared/library/sharedMath/include/public/sharedMath/MultiShape.h new file mode 100644 index 00000000..6c85ebf7 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/MultiShape.h @@ -0,0 +1 @@ +#include "../../src/shared/core/MultiShape.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/MxCifQuadTree.h b/engine/shared/library/sharedMath/include/public/sharedMath/MxCifQuadTree.h new file mode 100644 index 00000000..4f12dbe0 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/MxCifQuadTree.h @@ -0,0 +1 @@ +#include "../../src/shared/MxCifQuadTree.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/MxCifQuadTreeBounds.h b/engine/shared/library/sharedMath/include/public/sharedMath/MxCifQuadTreeBounds.h new file mode 100644 index 00000000..a43b781f --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/MxCifQuadTreeBounds.h @@ -0,0 +1 @@ +#include "../../src/shared/MxCifQuadTreeBounds.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/OrientedBox.h b/engine/shared/library/sharedMath/include/public/sharedMath/OrientedBox.h new file mode 100644 index 00000000..14639789 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/OrientedBox.h @@ -0,0 +1 @@ +#include "../../src/shared/core/OrientedBox.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/OrientedCircle.h b/engine/shared/library/sharedMath/include/public/sharedMath/OrientedCircle.h new file mode 100644 index 00000000..d20b9706 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/OrientedCircle.h @@ -0,0 +1 @@ +#include "../../src/shared/core/OrientedCircle.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/OrientedCylinder.h b/engine/shared/library/sharedMath/include/public/sharedMath/OrientedCylinder.h new file mode 100644 index 00000000..8096d28c --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/OrientedCylinder.h @@ -0,0 +1 @@ +#include "../../src/shared/core/OrientedCylinder.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/PackedArgb.h b/engine/shared/library/sharedMath/include/public/sharedMath/PackedArgb.h new file mode 100644 index 00000000..1502a147 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/PackedArgb.h @@ -0,0 +1 @@ +#include "../../src/shared/PackedArgb.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/PackedRgb.h b/engine/shared/library/sharedMath/include/public/sharedMath/PackedRgb.h new file mode 100644 index 00000000..6f09a6e0 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/PackedRgb.h @@ -0,0 +1 @@ +#include "../../src/shared/PackedRgb.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/PaletteArgb.h b/engine/shared/library/sharedMath/include/public/sharedMath/PaletteArgb.h new file mode 100644 index 00000000..fca0a190 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/PaletteArgb.h @@ -0,0 +1 @@ +#include "../../src/shared/PaletteArgb.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/PaletteArgbList.h b/engine/shared/library/sharedMath/include/public/sharedMath/PaletteArgbList.h new file mode 100644 index 00000000..e7625b6a --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/PaletteArgbList.h @@ -0,0 +1 @@ +#include "../../src/shared/PaletteArgbList.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Plane.h b/engine/shared/library/sharedMath/include/public/sharedMath/Plane.h new file mode 100644 index 00000000..196b38c4 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Plane.h @@ -0,0 +1 @@ +#include "../../src/shared/Plane.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Plane3d.h b/engine/shared/library/sharedMath/include/public/sharedMath/Plane3d.h new file mode 100644 index 00000000..329b262e --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Plane3d.h @@ -0,0 +1,2 @@ +#include "../../src/shared/core/Plane3d.h" + diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/PolySolver.h b/engine/shared/library/sharedMath/include/public/sharedMath/PolySolver.h new file mode 100644 index 00000000..2a92c69a --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/PolySolver.h @@ -0,0 +1 @@ +#include "../../src/shared/PolySolver.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/PositionVertexIndexer.h b/engine/shared/library/sharedMath/include/public/sharedMath/PositionVertexIndexer.h new file mode 100644 index 00000000..1b794625 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/PositionVertexIndexer.h @@ -0,0 +1 @@ +#include "../../src/shared/PositionVertexIndexer.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Quadratic.h b/engine/shared/library/sharedMath/include/public/sharedMath/Quadratic.h new file mode 100644 index 00000000..0d637e7f --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Quadratic.h @@ -0,0 +1 @@ +#include "../../src/shared/core/Quadratic.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Quaternion.h b/engine/shared/library/sharedMath/include/public/sharedMath/Quaternion.h new file mode 100644 index 00000000..86242a25 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Quaternion.h @@ -0,0 +1 @@ +#include "../../src/shared/Quaternion.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Range.h b/engine/shared/library/sharedMath/include/public/sharedMath/Range.h new file mode 100644 index 00000000..ebc3440a --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Range.h @@ -0,0 +1 @@ +#include "../../src/shared/core/Range.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/RangeLoop.h b/engine/shared/library/sharedMath/include/public/sharedMath/RangeLoop.h new file mode 100644 index 00000000..34120477 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/RangeLoop.h @@ -0,0 +1 @@ +#include "../../src/shared/core/RangeLoop.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Ray3d.h b/engine/shared/library/sharedMath/include/public/sharedMath/Ray3d.h new file mode 100644 index 00000000..54fe8190 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Ray3d.h @@ -0,0 +1 @@ +#include "../../src/shared/core/Ray3d.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Rectangle2d.h b/engine/shared/library/sharedMath/include/public/sharedMath/Rectangle2d.h new file mode 100644 index 00000000..0861b6a4 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Rectangle2d.h @@ -0,0 +1 @@ +#include "../../src/shared/Rectangle2d.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Ribbon3d.h b/engine/shared/library/sharedMath/include/public/sharedMath/Ribbon3d.h new file mode 100644 index 00000000..1cd1b903 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Ribbon3d.h @@ -0,0 +1,2 @@ +#include "../../src/shared/core/Ribbon3d.h" + diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Ring.h b/engine/shared/library/sharedMath/include/public/sharedMath/Ring.h new file mode 100644 index 00000000..3900a080 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Ring.h @@ -0,0 +1 @@ +#include "../../src/shared/core/Ring.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Segment3d.h b/engine/shared/library/sharedMath/include/public/sharedMath/Segment3d.h new file mode 100644 index 00000000..bd8ab9f2 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Segment3d.h @@ -0,0 +1 @@ +#include "../../src/shared/core/Segment3d.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/SetupSharedMath.h b/engine/shared/library/sharedMath/include/public/sharedMath/SetupSharedMath.h new file mode 100644 index 00000000..3c812ee8 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/SetupSharedMath.h @@ -0,0 +1 @@ +#include "../../src/shared/SetupSharedMath.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/ShapeUtils.h b/engine/shared/library/sharedMath/include/public/sharedMath/ShapeUtils.h new file mode 100644 index 00000000..1ac6b62f --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/ShapeUtils.h @@ -0,0 +1 @@ +#include "../../src/shared/core/ShapeUtils.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/SpatialSubdivision.h b/engine/shared/library/sharedMath/include/public/sharedMath/SpatialSubdivision.h new file mode 100644 index 00000000..e4662fb9 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/SpatialSubdivision.h @@ -0,0 +1 @@ +#include "../../src/shared/SpatialSubdivision.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Sphere.h b/engine/shared/library/sharedMath/include/public/sharedMath/Sphere.h new file mode 100644 index 00000000..4e5a7054 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Sphere.h @@ -0,0 +1 @@ +#include "../../src/shared/Sphere.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/SphereTree.h b/engine/shared/library/sharedMath/include/public/sharedMath/SphereTree.h new file mode 100644 index 00000000..89126966 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/SphereTree.h @@ -0,0 +1 @@ +#include "../../src/shared/SphereTree.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/SphereTreeNode.h b/engine/shared/library/sharedMath/include/public/sharedMath/SphereTreeNode.h new file mode 100644 index 00000000..7f658947 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/SphereTreeNode.h @@ -0,0 +1 @@ +#include "../../src/shared/SphereTreeNode.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/SseMath.h b/engine/shared/library/sharedMath/include/public/sharedMath/SseMath.h new file mode 100644 index 00000000..a469a23d --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/SseMath.h @@ -0,0 +1,5 @@ +#if defined(PLATFORM_WIN32) +#include "../../src/win32/SseMath.h" +#else +#error unsupported platform +#endif diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Torus.h b/engine/shared/library/sharedMath/include/public/sharedMath/Torus.h new file mode 100644 index 00000000..47e9cc7c --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Torus.h @@ -0,0 +1 @@ +#include "../../src/shared/core/Torus.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Transform.h b/engine/shared/library/sharedMath/include/public/sharedMath/Transform.h new file mode 100644 index 00000000..8d316203 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Transform.h @@ -0,0 +1 @@ +#include "../../src/shared/Transform.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Transform2d.h b/engine/shared/library/sharedMath/include/public/sharedMath/Transform2d.h new file mode 100644 index 00000000..040a7fe4 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Transform2d.h @@ -0,0 +1 @@ +#include "../../src/shared/Transform2d.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Triangle2d.h b/engine/shared/library/sharedMath/include/public/sharedMath/Triangle2d.h new file mode 100644 index 00000000..ec70307d --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Triangle2d.h @@ -0,0 +1 @@ +#include "../../src/shared/core/Triangle2d.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Triangle3d.h b/engine/shared/library/sharedMath/include/public/sharedMath/Triangle3d.h new file mode 100644 index 00000000..2e154225 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Triangle3d.h @@ -0,0 +1 @@ +#include "../../src/shared/core/Triangle3d.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Vector.h b/engine/shared/library/sharedMath/include/public/sharedMath/Vector.h new file mode 100644 index 00000000..73858df8 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Vector.h @@ -0,0 +1 @@ +#include "../../src/shared/Vector.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Vector2d.h b/engine/shared/library/sharedMath/include/public/sharedMath/Vector2d.h new file mode 100644 index 00000000..a0230499 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Vector2d.h @@ -0,0 +1 @@ +#include "../../src/shared/Vector2d.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/VectorArgb.h b/engine/shared/library/sharedMath/include/public/sharedMath/VectorArgb.h new file mode 100644 index 00000000..50b3512f --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/VectorArgb.h @@ -0,0 +1 @@ +#include "../../src/shared/VectorArgb.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/VectorRgba.h b/engine/shared/library/sharedMath/include/public/sharedMath/VectorRgba.h new file mode 100644 index 00000000..42bc63dd --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/VectorRgba.h @@ -0,0 +1 @@ +#include "../../src/shared/VectorRgba.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/Volume.h b/engine/shared/library/sharedMath/include/public/sharedMath/Volume.h new file mode 100644 index 00000000..4752cae8 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/Volume.h @@ -0,0 +1 @@ +#include "../../src/shared/Volume.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/WaveForm.h b/engine/shared/library/sharedMath/include/public/sharedMath/WaveForm.h new file mode 100644 index 00000000..c9c5e83e --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/WaveForm.h @@ -0,0 +1 @@ +#include "../../src/shared/WaveForm.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/WaveForm3D.h b/engine/shared/library/sharedMath/include/public/sharedMath/WaveForm3D.h new file mode 100644 index 00000000..851b7c72 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/WaveForm3D.h @@ -0,0 +1 @@ +#include "../../src/shared/WaveForm3D.h" diff --git a/engine/shared/library/sharedMath/include/public/sharedMath/YawedBox.h b/engine/shared/library/sharedMath/include/public/sharedMath/YawedBox.h new file mode 100644 index 00000000..2789fc25 --- /dev/null +++ b/engine/shared/library/sharedMath/include/public/sharedMath/YawedBox.h @@ -0,0 +1 @@ +#include "../../src/shared/core/YawedBox.h" diff --git a/engine/shared/library/sharedMath/src/CMakeLists.txt b/engine/shared/library/sharedMath/src/CMakeLists.txt new file mode 100644 index 00000000..e1c27ed1 --- /dev/null +++ b/engine/shared/library/sharedMath/src/CMakeLists.txt @@ -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} +) diff --git a/engine/shared/library/sharedMath/src/shared/CatmullRomSpline.cpp b/engine/shared/library/sharedMath/src/shared/CatmullRomSpline.cpp new file mode 100644 index 00000000..7dea669a --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/CatmullRomSpline.cpp @@ -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; +} + +// ============================================================================ diff --git a/engine/shared/library/sharedMath/src/shared/CatmullRomSpline.h b/engine/shared/library/sharedMath/src/shared/CatmullRomSpline.h new file mode 100644 index 00000000..a191cdc1 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/CatmullRomSpline.h @@ -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 diff --git a/engine/shared/library/sharedMath/src/shared/CompressedQuaternion.cpp b/engine/shared/library/sharedMath/src/shared/CompressedQuaternion.cpp new file mode 100644 index 00000000..d3cf61ba --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/CompressedQuaternion.cpp @@ -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 +#include + +// ====================================================================== + +#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((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(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(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(s_formatPrecisionInfo[m_formatPrecisionIndex].compressFactorTenBit * std::max(0.0f, uncompressedValue - m_baseValue)); + return std::min(cs_valueMaskTenBit, rawValue); + } + else + { + const uint32 rawValue = static_cast(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(s_formatPrecisionInfo[m_formatPrecisionIndex].compressFactorElevenBit * std::max(0.0f, uncompressedValue - m_baseValue)); + return std::min(cs_valueMaskElevenBit, rawValue); + } + else + { + const uint32 rawValue = static_cast(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(compressedValue & cs_valueMaskTenBit) * s_formatPrecisionInfo[m_formatPrecisionIndex].expandFactorTenBit); + else + return m_baseValue + (static_cast(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(compressedValue & cs_valueMaskElevenBit) * s_formatPrecisionInfo[m_formatPrecisionIndex].expandFactorElevenBit); + else + return m_baseValue + (static_cast(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(shift)); +} + +// ---------------------------------------------------------------------- + +inline float CompressedQuaternionNamespace::calculateRange(int baseShiftCount) +{ + DEBUG_FATAL(baseShiftCount < 0, ("bad baseShiftCount arg [%d].", baseShiftCount)); + return 4.0f / static_cast(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::max(); + float closestBaseValue = std::numeric_limits::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(s_formatPrecisionInfo[baseShiftCount].baseIndexMask & static_cast(baseIndex)) != baseIndex, ("base index %d not valid for format with baseShift = %d.", baseIndex, baseShiftCount)); + format = static_cast(s_formatPrecisionInfo[baseShiftCount].formatId | static_cast(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(BINARY3(0011, 1111, 1111)) / halfRange; + s_formatPrecisionInfo[baseShiftCount].expandFactorElevenBit = halfRange / static_cast(BINARY3(0011, 1111, 1111)); + + s_formatPrecisionInfo[baseShiftCount].compressFactorTenBit = static_cast(BINARY3(0001, 1111, 1111)) / halfRange; + s_formatPrecisionInfo[baseShiftCount].expandFactorTenBit = halfRange / static_cast(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(formatId | static_cast(i)); + float const baseValue = - 1.0f + (i + 1) * baseSeparation; + + VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(0, static_cast(formatIndex), cs_maxFormatValue); + s_formatData[formatIndex].install(baseValue, static_cast(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(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::max(); + float maxX = -std::numeric_limits::max(); + + float minY = std::numeric_limits::max(); + float maxY = -std::numeric_limits::max(); + + float minZ = std::numeric_limits::max(); + float maxZ = -std::numeric_limits::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(m_data))); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedMath/src/shared/CompressedQuaternion.h b/engine/shared/library/sharedMath/src/shared/CompressedQuaternion.h new file mode 100644 index 00000000..766fd2b7 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/CompressedQuaternion.h @@ -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::fwd QuaternionVector; + typedef stdvector::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 diff --git a/engine/shared/library/sharedMath/src/shared/ConfigSharedMath.cpp b/engine/shared/library/sharedMath/src/shared/ConfigSharedMath.cpp new file mode 100644 index 00000000..cbc48ae2 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/ConfigSharedMath.cpp @@ -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; +} + +// ====================================================================== + + diff --git a/engine/shared/library/sharedMath/src/shared/ConfigSharedMath.h b/engine/shared/library/sharedMath/src/shared/ConfigSharedMath.h new file mode 100644 index 00000000..2b85528c --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/ConfigSharedMath.h @@ -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 diff --git a/engine/shared/library/sharedMath/src/shared/FirstSharedMath.h b/engine/shared/library/sharedMath/src/shared/FirstSharedMath.h new file mode 100644 index 00000000..c5397bc7 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/FirstSharedMath.h @@ -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 + diff --git a/engine/shared/library/sharedMath/src/shared/IndexedTriangleList.cpp b/engine/shared/library/sharedMath/src/shared/IndexedTriangleList.cpp new file mode 100644 index 00000000..06a0229c --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/IndexedTriangleList.cpp @@ -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 +#include + +// ====================================================================== + +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), + m_indices(new std::vector) +{ +} + +// ---------------------------------------------------------------------- + +IndexedTriangleList::IndexedTriangleList(Iff & iff) : + m_mergeVertices(false), + m_epsilon(0.0f), + m_vertices(new std::vector), + m_indices(new std::vector) +{ + load(iff); +} + +// ---------------------------------------------------------------------- + +IndexedTriangleList::~IndexedTriangleList() +{ + delete m_vertices; + delete m_indices; +} + +// ---------------------------------------------------------------------- + +const std::vector &IndexedTriangleList::getVertices() const +{ + return *m_vertices; +} + +// ---------- + +const std::vector &IndexedTriangleList::getIndices() const +{ + return *m_indices; +} + +// ---------------------------------------------------------------------- + +std::vector &IndexedTriangleList::getVertices() +{ + return *m_vertices; +} + +// ---------- + +std::vector &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( iff.getChunkLengthLeft(3 * sizeof(float)) ); + DEBUG_FATAL(!numberOfVertices, ("No vertices")); + m_vertices->resize(numberOfVertices); + iff.read_floatVector( static_cast(numberOfVertices), &(*m_vertices)[0]); + } + iff.exitChunk(TAG_VERT); + + iff.enterChunk(TAG_INDX); + { + const uint numberOfIndices = static_cast( 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((*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 &indices) +{ + indices.reserve( static_cast(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(m_vertices->size())); + m_vertices->push_back(vertices[i]); + } + else + indices.push_back( static_cast(j) ); + } + } + else + { + for (int i = 0; i < numberOfVertices; ++i) + { + indices.push_back(static_cast(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 vertexIndices; + addVertices(vertices, numberOfVertices, vertexIndices); + + for (uint i = 0; i < static_cast(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 vertexIndices; + addVertices(vertices, numberOfVertices, vertexIndices); + + const uint triangleCount = static_cast(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 vertexIndices; + addVertices(vertices, numberOfVertices, vertexIndices); + + const uint triangleCount = static_cast(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 vertexIndices; + addVertices(vertices, numberOfVertices, vertexIndices); + + for (uint i = 0; i < static_cast(numberOfIndices); ++i) + { + uint index = static_cast(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 vertexIndices; + addVertices(vertices, numberOfVertices, vertexIndices); + + const uint triangleCount = static_cast(numberOfIndices) - 2; + for (uint i = 0; i < triangleCount; ++i) + { + if (i & 1) + { + m_indices->push_back(vertexIndices[ static_cast(indices[i+0]) ]); + m_indices->push_back(vertexIndices[ static_cast(indices[i+2]) ]); + m_indices->push_back(vertexIndices[ static_cast(indices[i+1]) ]); + } + else + { + m_indices->push_back(vertexIndices[ static_cast(indices[i+0]) ]); + m_indices->push_back(vertexIndices[ static_cast(indices[i+1]) ]); + m_indices->push_back(vertexIndices[ static_cast(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 vertexIndices; + addVertices(vertices, numberOfVertices, vertexIndices); + + const uint triangleCount = static_cast(numberOfIndices) - 2; + for (uint i = 0; i < triangleCount; ++i) + { + m_indices->push_back(vertexIndices[ static_cast(indices[0])]); + m_indices->push_back(vertexIndices[ static_cast(indices[i+1])]); + m_indices->push_back(vertexIndices[ static_cast(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 const & indices, Vector & result) const +{ + bool found = false; + + Vector shortenedEnd(end); + Vector const direction(end - start); + + Vector normal; + Plane plane; + Vector intersection; + + std::vector const & vertices = *m_vertices; + + uint const numberOfIndices = indices.size(); + + for (int index = 0; static_cast(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::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; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedMath/src/shared/IndexedTriangleList.h b/engine/shared/library/sharedMath/src/shared/IndexedTriangleList.h new file mode 100644 index 00000000..9c43c4f5 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/IndexedTriangleList.h @@ -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::fwd &getVertices() const; + const stdvector::fwd &getIndices() const; + + stdvector::fwd &getVertices(); + stdvector::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::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::fwd &indices); + +private: + + bool m_mergeVertices; + float m_epsilon; + stdvector::fwd * const m_vertices; + stdvector::fwd * const m_indices; +}; + +// ====================================================================== + +inline void IndexedTriangleList::allowVertexMerging(bool mergeVertices) +{ + m_mergeVertices = mergeVertices; +} + +// ---------------------------------------------------------------------- + +inline void IndexedTriangleList::setVertexMergeEpsilon(float epsilon) +{ + m_epsilon = epsilon; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedMath/src/shared/Line2d.h b/engine/shared/library/sharedMath/src/shared/Line2d.h new file mode 100644 index 00000000..55abc2e6 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/Line2d.h @@ -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 diff --git a/engine/shared/library/sharedMath/src/shared/MxCifQuadTree.cpp b/engine/shared/library/sharedMath/src/shared/MxCifQuadTree.cpp new file mode 100644 index 00000000..81aa4012 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/MxCifQuadTree.cpp @@ -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 & 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 & 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::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 & 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_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 & 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_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 & 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_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 + +//============================================================================== diff --git a/engine/shared/library/sharedMath/src/shared/MxCifQuadTree.h b/engine/shared/library/sharedMath/src/shared/MxCifQuadTree.h new file mode 100644 index 00000000..8c0aa778 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/MxCifQuadTree.h @@ -0,0 +1,163 @@ +// ====================================================================== +// +// MxCifQuadTree.h +// +// Copyright 2002, Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_MxCifQuadTree_H +#define INCLUDED_MxCifQuadTree_H + + +#include + + +//============================================================================== + +/******************************************************************************* + + 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 & objects) const; + void getAllObjects(std::vector & 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 & objects) const = 0; + void getAllObjects(std::vector & 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 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 & 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 & 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 diff --git a/engine/shared/library/sharedMath/src/shared/MxCifQuadTreeBounds.cpp b/engine/shared/library/sharedMath/src/shared/MxCifQuadTreeBounds.cpp new file mode 100644 index 00000000..bb17833f --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/MxCifQuadTreeBounds.cpp @@ -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 diff --git a/engine/shared/library/sharedMath/src/shared/MxCifQuadTreeBounds.h b/engine/shared/library/sharedMath/src/shared/MxCifQuadTreeBounds.h new file mode 100644 index 00000000..5ac6d4db --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/MxCifQuadTreeBounds.h @@ -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 diff --git a/engine/shared/library/sharedMath/src/shared/PackedArgb.cpp b/engine/shared/library/sharedMath/src/shared/PackedArgb.cpp new file mode 100644 index 00000000..f06ed21a --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/PackedArgb.cpp @@ -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(::linearInterpolate(static_cast(color1.getA()), static_cast(color2.getA()), t)), + static_cast(::linearInterpolate(static_cast(color1.getR()), static_cast(color2.getR()), t)), + static_cast(::linearInterpolate(static_cast(color1.getG()), static_cast(color2.getG()), t)), + static_cast(::linearInterpolate(static_cast(color1.getB()), static_cast(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); +} + +// ====================================================================== + diff --git a/engine/shared/library/sharedMath/src/shared/PackedArgb.h b/engine/shared/library/sharedMath/src/shared/PackedArgb.h new file mode 100644 index 00000000..731c6e32 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/PackedArgb.h @@ -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(a) << 24 | + static_cast(r) << 16 | + static_cast(g) << 8 | + static_cast(b) << 0; +} + +// ---------------------------------------------------------------------- + +inline uint32 PackedArgb::convert(float a, float r, float g, float b) +{ + return convert(static_cast(a * 255.0f), static_cast(r * 255.0f), static_cast(g * 255.0f), static_cast(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((m_argb >> 24) & 0xff); +} + +// ---------------------------------------------------------------------- +/** + * Return the red component. + * @return the red component. + */ + +inline uint8 PackedArgb::getR() const +{ + return static_cast((m_argb >> 16) & 0xff); +} + +// ---------------------------------------------------------------------- +/** + * Return the green component. + * @return the green component. + */ + +inline uint8 PackedArgb::getG() const +{ + return static_cast((m_argb >> 8) & 0xff); +} + +// ---------------------------------------------------------------------- +/** + * Return the blue component. + * @return the blue component. + */ + +inline uint8 PackedArgb::getB() const +{ + return static_cast((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(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(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(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(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 diff --git a/engine/shared/library/sharedMath/src/shared/PackedRgb.cpp b/engine/shared/library/sharedMath/src/shared/PackedRgb.cpp new file mode 100644 index 00000000..b4c65e54 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/PackedRgb.cpp @@ -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 (r) * oo255, + static_cast (g) * oo255, + static_cast (b) * oo255); +} + +//------------------------------------------------------------------- + +void PackedRgb::convert (const VectorArgb& color) +{ + r = static_cast (color.r * 255.f); + g = static_cast (color.g * 255.f); + b = static_cast (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 (::linearInterpolate (static_cast (color1.r), static_cast (color2.r), t)), + static_cast (::linearInterpolate (static_cast (color1.g), static_cast (color2.g), t)), + static_cast (::linearInterpolate (static_cast (color1.b), static_cast (color2.b), t))); +} + +//=================================================================== + diff --git a/engine/shared/library/sharedMath/src/shared/PackedRgb.h b/engine/shared/library/sharedMath/src/shared/PackedRgb.h new file mode 100644 index 00000000..e74d9cec --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/PackedRgb.h @@ -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(r) << 16) | (static_cast(g) << 8) | (static_cast(b) << 0); +} + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedMath/src/shared/PaletteArgb.cpp b/engine/shared/library/sharedMath/src/shared/PaletteArgb.cpp new file mode 100644 index 00000000..097826be --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/PaletteArgb.cpp @@ -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 +#include +#include + +// ====================================================================== + +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(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(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(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(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(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(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(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::max(); + int minIndex = -1; + + const int tr = static_cast(targetColor.getR()); + const int tg = static_cast(targetColor.getG()); + const int tb = static_cast(targetColor.getB()); + const int ta = static_cast(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(it->getR()); + const int cg = static_cast(it->getG()); + const int cb = static_cast(it->getB()); + const int ca = static_cast(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(buffer[bufferPosition + 0]) << 0) | + (static_cast(buffer[bufferPosition + 1]) << 8) | + (static_cast(buffer[bufferPosition + 2]) << 16) | + (static_cast(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(buffer[bufferPosition + 0]) << 0) | + (static_cast(buffer[bufferPosition + 1]) << 8) | + (static_cast(buffer[bufferPosition + 2]) << 16) | + (static_cast(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(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(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(buffer[bufferPosition + 0]) << 0) | + (static_cast(buffer[bufferPosition + 1]) << 8); + bufferPosition += 2; + + if (static_cast(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(entryCount)); + + for (uint i = 0; i < entryCount; ++i) + { + PackedArgb &entry = (*m_entries)[static_cast(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(entryCount); + + *(buffer++) = static_cast((riffChunkLength >> 0) & 0xff); + *(buffer++) = static_cast((riffChunkLength >> 8) & 0xff); + *(buffer++) = static_cast((riffChunkLength >> 16) & 0xff); + *(buffer++) = static_cast((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(entryCount); + + *(buffer++) = static_cast((paletteChunkLength >> 0) & 0xff); + *(buffer++) = static_cast((paletteChunkLength >> 8) & 0xff); + *(buffer++) = static_cast((paletteChunkLength >> 16) & 0xff); + *(buffer++) = static_cast((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(componentCount); + + // write entry count + const uint uiEntryCount = static_cast(entryCount); + + *(buffer++) = static_cast((uiEntryCount >> 0) & 0xff); + *(buffer++) = static_cast((uiEntryCount >> 8) & 0xff); + + // write data + for (uint i = 0; i < uiEntryCount; ++i) + { + const PackedArgb &entry = (*m_entries)[static_cast(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; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedMath/src/shared/PaletteArgb.h b/engine/shared/library/sharedMath/src/shared/PaletteArgb.h new file mode 100644 index 00000000..4df62ae0 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/PaletteArgb.h @@ -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::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::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 diff --git a/engine/shared/library/sharedMath/src/shared/PaletteArgbList.cpp b/engine/shared/library/sharedMath/src/shared/PaletteArgbList.cpp new file mode 100644 index 00000000..0e176649 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/PaletteArgbList.cpp @@ -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 + +// ====================================================================== + +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(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; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedMath/src/shared/PaletteArgbList.h b/engine/shared/library/sharedMath/src/shared/PaletteArgbList.h new file mode 100644 index 00000000..f064f7a8 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/PaletteArgbList.h @@ -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::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 diff --git a/engine/shared/library/sharedMath/src/shared/Plane.cpp b/engine/shared/library/sharedMath/src/shared/Plane.cpp new file mode 100644 index 00000000..de9e491f --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/Plane.cpp @@ -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); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedMath/src/shared/Plane.h b/engine/shared/library/sharedMath/src/shared/Plane.h new file mode 100644 index 00000000..50559e85 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/Plane.h @@ -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 diff --git a/engine/shared/library/sharedMath/src/shared/PolySolver.cpp b/engine/shared/library/sharedMath/src/shared/PolySolver.cpp new file mode 100644 index 00000000..06515452 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/PolySolver.cpp @@ -0,0 +1,319 @@ +// Polynomial solver code adapted from Graphics Gems version +// by Jochen Schwarze + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/PolySolver.h" + +#include +#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; +} diff --git a/engine/shared/library/sharedMath/src/shared/PolySolver.h b/engine/shared/library/sharedMath/src/shared/PolySolver.h new file mode 100644 index 00000000..6cc75e85 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/PolySolver.h @@ -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 + diff --git a/engine/shared/library/sharedMath/src/shared/PositionVertexIndexer.cpp b/engine/shared/library/sharedMath/src/shared/PositionVertexIndexer.cpp new file mode 100644 index 00000000..d8cefe07 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/PositionVertexIndexer.cpp @@ -0,0 +1,146 @@ +// ====================================================================== +// +// PositionVertexIndexer.cpp +// copyright 2002, Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/PositionVertexIndexer.h" + +#include "sharedFoundation/Crc.h" + +#include +#include +#include + +// ====================================================================== + +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(numberOfVertices)); +} + +// ---------------------------------------------------------------------- + +int PositionVertexIndexer::addVertex(Vector const & vertex) +{ + uint32 const key = Crc::calculate(&vertex,sizeof(vertex)); + + + std::pair 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(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(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(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(index)]; +} + +// ---------------------------------------------------------------------- + +Vector & PositionVertexIndexer::getVertex(int const index) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfVertices()); + return (*m_vertices)[static_cast(index)]; +} + +// ---------------------------------------------------------------------- + +PositionVertexIndexer::VectorVector const & PositionVertexIndexer::getVertices() const +{ + return *m_vertices; +} + +// ---------------------------------------------------------------------- + +PositionVertexIndexer::VectorVector & PositionVertexIndexer::getVertices() +{ + return *m_vertices; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedMath/src/shared/PositionVertexIndexer.h b/engine/shared/library/sharedMath/src/shared/PositionVertexIndexer.h new file mode 100644 index 00000000..8fc181d5 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/PositionVertexIndexer.h @@ -0,0 +1,53 @@ +// ====================================================================== +// +// PositionVertexIndexer.h +// Copyright 2004, Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_PositionVertexIndexer_H +#define INCLUDED_PositionVertexIndexer_H + +// ====================================================================== + +#include "sharedMath/Vector.h" + +#include + +// ====================================================================== + +class PositionVertexIndexer +{ +public: + typedef stdvector::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 VertexIndexMap; + + VectorVector * m_vertices; + VertexIndexMap * m_indexMap; +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedMath/src/shared/Quaternion.cpp b/engine/shared/library/sharedMath/src/shared/Quaternion.cpp new file mode 100644 index 00000000..38ce35b6 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/Quaternion.cpp @@ -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 V2, s1*V2 + s2*V1 + V1 V2) + // where = dot product binary operator and + // = 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)); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedMath/src/shared/Quaternion.h b/engine/shared/library/sharedMath/src/shared/Quaternion.h new file mode 100644 index 00000000..c4ce2bb5 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/Quaternion.h @@ -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 diff --git a/engine/shared/library/sharedMath/src/shared/Rectangle2d.cpp b/engine/shared/library/sharedMath/src/shared/Rectangle2d.cpp new file mode 100644 index 00000000..ec30e228 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/Rectangle2d.cpp @@ -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 + +//=================================================================== + +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; +} + +//=================================================================== + diff --git a/engine/shared/library/sharedMath/src/shared/Rectangle2d.h b/engine/shared/library/sharedMath/src/shared/Rectangle2d.h new file mode 100644 index 00000000..a8c4dcbd --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/Rectangle2d.h @@ -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 diff --git a/engine/shared/library/sharedMath/src/shared/SetupSharedMath.cpp b/engine/shared/library/sharedMath/src/shared/SetupSharedMath.cpp new file mode 100644 index 00000000..eb4de955 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/SetupSharedMath.cpp @@ -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(); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedMath/src/shared/SetupSharedMath.h b/engine/shared/library/sharedMath/src/shared/SetupSharedMath.h new file mode 100644 index 00000000..2748426b --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/SetupSharedMath.h @@ -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 diff --git a/engine/shared/library/sharedMath/src/shared/SpatialSubdivision.cpp b/engine/shared/library/sharedMath/src/shared/SpatialSubdivision.cpp new file mode 100644 index 00000000..e4e73c95 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/SpatialSubdivision.cpp @@ -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; +} + +//----------------------------------------------------------------------- + diff --git a/engine/shared/library/sharedMath/src/shared/SpatialSubdivision.h b/engine/shared/library/sharedMath/src/shared/SpatialSubdivision.h new file mode 100644 index 00000000..4aba185d --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/SpatialSubdivision.h @@ -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 SphereTree : public SpatialSubdivision + \endcode + + or the client Quadtree as + \code + class QuadTree : public SpatialSubdivision + \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 SpatialSubdivisionFilter +{ +public: + virtual ~SpatialSubdivisionFilter() {} + virtual bool operator()(const ObjectType &) const=0; +}; + +template +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::fwd & results) const = 0; + virtual void findInRange (const Vector & origin, const float distance, const SpatialSubdivisionFilter &filter, typename stdvector::fwd & results) const = 0; + virtual void findOnRay (const Vector & begin, const Vector & dir, typename stdvector::fwd & results) const = 0; + virtual void findOnSegment (const Vector & begin, const Vector & end, typename stdvector::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 +inline SpatialSubdivision::SpatialSubdivision() +{ +} + +//----------------------------------------------------------------------- +/** + @brief destroy a SpatialSubdivision template instance + + This destructor doesn't do anything. It is present for completeness. + + @author Justin Randall +*/ +template +inline SpatialSubdivision::~SpatialSubdivision() +{ +} + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_SpatialSubdivision_H diff --git a/engine/shared/library/sharedMath/src/shared/Sphere.cpp b/engine/shared/library/sharedMath/src/shared/Sphere.cpp new file mode 100644 index 00000000..f99fd0ff --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/Sphere.cpp @@ -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; +} + + +// ====================================================================== + diff --git a/engine/shared/library/sharedMath/src/shared/Sphere.h b/engine/shared/library/sharedMath/src/shared/Sphere.h new file mode 100644 index 00000000..90909d5f --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/Sphere.h @@ -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 diff --git a/engine/shared/library/sharedMath/src/shared/SphereTree.h b/engine/shared/library/sharedMath/src/shared/SphereTree.h new file mode 100644 index 00000000..46ffbaa9 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/SphereTree.h @@ -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 SphereTree : public SpatialSubdivision +{ +public: + typedef SphereTreeNode 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 & results) const; + void dumpSphereTree (std::vector > & results) const; + void dumpSphereTreeNodes(std::vector > & results) const; + void dumpSphereTreeObjs (std::vector > & results) const; + void dumpEdgeList (std::vector & results) const; + virtual void findInRange (const Vector & origin, const float distance, std::vector & results) const; + virtual void findInRange (const Vector & origin, const float distance, std::vector & results, int & testCounter) const; + virtual void findInRange (const Vector & origin, const float distance, const SpatialSubdivisionFilter &filter, std::vector & results) const; + virtual void findInRange (const Vector & origin, const float distance, const SpatialSubdivisionFilter &filter, std::vector & results, int & testCounter) const; + virtual void findOnRay (const Vector & begin, const Vector & dir, std::vector & results) const; + virtual void findOnSegment (const Vector & begin, const Vector & end, std::vector & results) const; + virtual void findOnSegment(Vector const & begin, Vector const & end, SpatialSubdivisionFilter const & filter, std::vector & results) const; + virtual void findAtPoint (const Vector & point, std::vector & results) const; + virtual void findInRange (const Capsule & range, std::vector & results) const; + virtual void findInRange (const Capsule & range, const SpatialSubdivisionFilter &filter, std::vector & 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::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 +inline SphereTree::SphereTree() : +root() +{ +} + +//----------------------------------------------------------------------- +/** + @brief destroy the sphere tree + + Doesn't do anything. Included here for completeness. +*/ +template +inline SphereTree::~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 +inline SpatialSubdivisionHandle * SphereTree::addObject(ObjectType object) +{ + return root.addObject(object); +} + +//----------------------------------------------------------------------- +/** + @brief not implemented + + @todo implement! +*/ +template +inline const bool SphereTree::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 +inline void SphereTree::dumpSphereTreeObjects(std::vector & results) const +{ + root.dumpSphereTreeObjects(results); +} + +template +inline void SphereTree::dumpSphereTree(std::vector > & results) const +{ + root.dumpSphereTree(results); +} + +template +inline void SphereTree::dumpSphereTreeNodes(std::vector > & results) const +{ + root.dumpSphereTreeNodes(results); +} + +template +inline void SphereTree::dumpSphereTreeObjs(std::vector > & results) const +{ + root.dumpSphereTreeObjs(results); +} + +template +inline void SphereTree::dumpEdgeList(std::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 +inline void SphereTree::findInRange(const Vector & origin, const float distance, std::vector & results) const +{ + const Sphere range(origin, distance); + root.findInRange(range, results); +} + +template +inline void SphereTree::findInRange(const Vector & origin, const float distance, std::vector & 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 +inline void SphereTree::findInRange(const Vector & origin, const float distance, const SpatialSubdivisionFilter &filter, std::vector & results) const +{ + const Sphere range(origin, distance); + root.findInRange(range, filter, results); +} + +template +inline void SphereTree::findInRange(const Vector & origin, const float distance, const SpatialSubdivisionFilter &filter, std::vector & 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 +inline void SphereTree::findOnRay(const Vector & begin, const Vector & dir, std::vector & 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 +inline void SphereTree::findOnSegment(const Vector & begin, const Vector & end, std::vector & results) const +{ + root.findOnSegment(begin, end, results); +} + +//----------------------------------------------------------------------- + +template +inline void SphereTree::findOnSegment(Vector const & begin, Vector const & end, SpatialSubdivisionFilter const & filter, std::vector & 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 +inline void SphereTree::findAtPoint(const Vector & point, std::vector & results) const +{ + root.findAtPoint(point,results); +} + +//----------------------------------------------------------------------- + +template +inline void SphereTree::findInRange(const Capsule & range, std::vector & results) const +{ + root.findInRange(range, results); +} + +//----------------------------------------------------------------------- + +template +inline void SphereTree::findInRange(const Capsule & range, const SpatialSubdivisionFilter &filter, std::vector & 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 +inline bool SphereTree::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 +inline bool SphereTree::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 +inline bool SphereTree::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 +inline bool SphereTree::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 +inline void SphereTree::move(SpatialSubdivisionHandle *object) +{ + if (object) + static_cast::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 +inline void SphereTree::removeObject(SpatialSubdivisionHandle * object) +{ + if (object) + static_cast::NodeHandle *>(object)->removeObject(); +} + +// ---------------------------------------------------------------------- + +template +inline void SphereTree::validate() const +{ + root.validate(); +} + +// ---------------------------------------------------------------------- + +template +inline int SphereTree::getNodeCount() const +{ + return root.getNodeCount(); +} + +// ---------------------------------------------------------------------- + +template +inline bool SphereTree::empty() const +{ + return root.empty(); +} + +// ---------------------------------------------------------------------- + +template +inline int SphereTree::getObjectCount() const +{ + return root.getObjectCount(); +} + +// ---------------------------------------------------------------------- + +template +inline void SphereTree::apply(typename SphereTreeNode::NodeFunctor N) +{ + return root.apply(N); +} + +//----------------------------------------------------------------------- + +template +inline bool SphereTree::isWithin (Vector const & position) const +{ + return root.isWithin (position); +} + +// ---------------------------------------------------------------------- + +template +Sphere const &SphereTree::getRealSphere() const +{ + return root.getRealSphere(); +} + +// ====================================================================== + +#endif // _INCLUDED_SphereTree_H + diff --git a/engine/shared/library/sharedMath/src/shared/SphereTreeNode.h b/engine/shared/library/sharedMath/src/shared/SphereTreeNode.h new file mode 100644 index 00000000..7cb4f053 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/SphereTreeNode.h @@ -0,0 +1,1652 @@ +// SphereTreeNode.h +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_SphereTreeNode_H +#define _INCLUDED_SphereTreeNode_H + +//----------------------------------------------------------------------- + +#include "sharedMath/Sphere.h" +#include "sharedMath/Capsule.h" +#include "sharedMath/SpatialSubdivision.h" + +#include + +static const float SphereTreeEpsilon = 0.01f; +static const float childScaleFactor = 0.25f; +static const float leafScaleFactor = 10.0f; + +//----------------------------------------------------------------------- +/** + @brief support class that tracks a vector of pointers + + This is used internally by the SphereTreeNode and + SphereTreeNode::Handle classes. A static vector of free + SphereTreeNode and SphereTreeNode::Handle objects is maintained to + limit allocations as the tree reorganizes itself. + + Because the SphereTree is not a singleton class, it is possible + to share free nodes between instances. The order of destruction + would otherwise be undefinable. Forcing a static instance + of a VectorPointerPool within a function of a node or handle + will gaurantee proper destruction during program termnination. +*/ +template +class VectorPointerPool +{ +public: + VectorPointerPool(); + ~VectorPointerPool(); + std::vector *v; +}; + +//----------------------------------------------------------------------- + +template +VectorPointerPool::VectorPointerPool() +{ + // we were having a client crash bug caused by one of these objects getting constructed twice. + // basically, only one static instance for the type existed, but the complier had two instances + // of the flag that indicated whether or not the object had been constructed. by doing this, + // we can avoid any work on the second construction, and know to only really destruct the object + // once. + if (!v) + v = new std::vector; +} + +//----------------------------------------------------------------------- + +template +VectorPointerPool::~VectorPointerPool() +{ + if (v) + { + typename std::vector::iterator i; + for(i = v->begin(); i != v->end(); ++i) + { + ValueType * vt = (*i); + delete vt; + } + + delete v; + v = NULL; + } +} + +//----------------------------------------------------------------------- +/** + @brief Workhorse of the SphereTree + + Most of the functionality of the SphereTree is implemened in the + SphereTreeNode. A SphereTreeNode represents a sphere in 3-space which + can contain smaller child spheres or objects whose bounding spheres + are completely contained in the node sphere. + +*/ +template +class SphereTreeNode +{ +public: + SphereTreeNode (); + ~SphereTreeNode (); + + SpatialSubdivisionHandle * addObject (ObjectType object); + void dumpSphereTreeObjects(std::vector & results) const; + void dumpSphereTree (std::vector > & results) const; + void dumpSphereTreeNodes(std::vector > & results) const; + void dumpSphereTreeObjs (std::vector > & results) const; + void dumpEdgeList (std::vector & results) const; + const bool canContain (const Sphere & sphere) const; + const bool canContain (const Vector & point) const; + void findInRange (const Sphere & range, std::vector & results) const; + void findInRange (const Sphere & range, std::vector & results, int & testCounter ) const; + void findInRange (const Sphere & range, const SpatialSubdivisionFilter &filter, std::vector & results) const; + void findInRange (const Sphere & range, const SpatialSubdivisionFilter &filter, std::vector & results, int & testCounter) const; + void findOnRay (const Vector & begin, const Vector & dir, std::vector & results) const; + void findOnSegment (const Vector & begin, const Vector & end, std::vector & results) const; + void findOnSegment(Vector const & begin, Vector const & end, SpatialSubdivisionFilter const & filter, std::vector & results) const; + void findAtPoint (const Vector & point, std::vector & results) const; + void findInRange (const Capsule & capsule, std::vector & results) const; + void findInRange (const Capsule & capsule, SpatialSubdivisionFilter const & filter, std::vector & results) const; + + bool findClosest (const Vector & begin, float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance ) const; + bool findClosest (const Vector & begin, float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance, int & testCounter) const; + bool findClosest2d (const Vector & begin, float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance ) const; + bool findClosest2d (const Vector & begin, float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance, int & testCounter) const; + + void validate () const; + int getNodeCount () const; + bool empty () const; + int getObjectCount () const; + + typedef void (*NodeFunctor)(SphereTreeNode * node); + + void apply (NodeFunctor N); + + bool isWithin (Vector const & position) const; + Sphere const & getRealSphere () const; + +private: + + void reinitialize(); + + SphereTreeNode & operator = (const SphereTreeNode & rhs); + SphereTreeNode (const SphereTreeNode & source); + + void getContents (std::vector & results); + void getContents (const SpatialSubdivisionFilter &filter, std::vector & results); + static std::vector & getNodeFreeList (); + static SphereTreeNode * getNode (); + static void releaseNode (SphereTreeNode * node); + void resizeRealSphere (const float newRadius); + void unlinkNode (SphereTreeNode * node); + + SphereTreeNode * getParent (); + SphereTreeNode const * getParent () const; + void setParent (SphereTreeNode * newParent); + + Sphere getSphere (ObjectType object) const; + + bool isValidSphere (Sphere const & sphere) const; + + void internalResizeRealSphere (float newRadius); + +private: + std::vector children; + std::vector contents; + Sphere maxSphere; + SphereTreeNode * parent; + Sphere realSphere; + +public: + //----------------------------------------------------------------------- + // NodeHandle Inner Class + // + /** @brief a node handle inner class, returned by addObject and fed + to the SphereTreeNode via the SpatialDatabase interfaces. It's used + to quickly identify a sphere tree node to expedite operations on + objects in the tree. + */ + class NodeHandle : public SpatialSubdivisionHandle + { + public: + NodeHandle (){}; + ~NodeHandle (){}; + + SphereTreeNode * getNode () const { return node; }; + ObjectType getObject () const { return object; }; + void setNode (SphereTreeNode * newNode) { node = newNode; }; + void setObject (ObjectType newObject) {object = newObject; }; + + // accomodate MSVC's inability to inline template inner classes outside the + // outer template class + static std::vector & getHandleFreeList() + { + static VectorPointerPool freeList; + return *(freeList.v); + }; + + static NodeHandle * getNodeHandle() + { + NodeHandle * result = 0; + if(! getHandleFreeList().empty()) + { + result = getHandleFreeList().back(); + getHandleFreeList().pop_back(); + } + else + { + result = ExtentAccessor::allocateNodeHandle(); + } + return result; + }; + + void move() + { + if (node) + node->move(this); + else + { + WARNING_STRICT_FATAL(true, ("SphereTree::move was invoked for an object, but the real sphere tree node it refers to is null.")); + } + }; + + static void releaseHandle(NodeHandle * oldHandle) + { + getHandleFreeList().push_back(oldHandle); + }; + + void removeObject() + { + if(node) + { + node->removeObject(this); + releaseHandle(this); + } + }; + + private: + SphereTreeNode * node; + ObjectType object; + }; + // End NodeHandle Inner Class + //----------------------------------------------------------------------- + +public: + void move (NodeHandle * handle); + void relocateObject (NodeHandle * handle, const Sphere & sphere); + void removeObject (NodeHandle * object); +}; + +//----------------------------------------------------------------------- + +template +inline SphereTreeNode::SphereTreeNode() : +children(), +contents(), +maxSphere(Sphere(Vector::zero, SphereTreeEpsilon)), +parent(/*newParent*/ 0), +realSphere() +{ +} + +//----------------------------------------------------------------------- + +template +inline void SphereTreeNode::reinitialize() +{ + children.clear(); + contents.clear(); + maxSphere = Sphere(Vector::zero, SphereTreeEpsilon); + parent = 0; + realSphere = Sphere::zero; +} + +//----------------------------------------------------------------------- + +template +inline SphereTreeNode::~SphereTreeNode() +{ + // delete child nodes + typename std::vector::iterator i; + for(i = children.begin(); i != children.end(); ++i) + { + SphereTreeNode * c = (*i); + delete c; + } + children.clear(); + + parent = 0; + contents.clear(); +} + +//----------------------------------------------------------------------- + +template +inline SpatialSubdivisionHandle * SphereTreeNode::addObject(ObjectType object) +{ + const Sphere & sphere = getSphere(object); + + if(!isValidSphere(sphere)) + { + WARNING_STRICT_FATAL(true, ("SphereTreeNode::addObject - sphere for the object being added is invalid")); + return NULL; + } + + SphereTreeNode * candidateNode = 0; + NodeHandle * result = 0; + + if(sphere.getRadius() > 0.0f) + { + // quick check to keep supersphere distribution over + // used world space to about 16 spheres (there may be + // more with overlap, maybe a lot less depending on + // object distribution) + if(!parent) + { + if(sphere.getRadius() * leafScaleFactor > maxSphere.getRadius()) + { + maxSphere.setRadius(sphere.getRadius() * leafScaleFactor); + } + + // dirty hack.. floating point error becomes intolerable + // at distances over 16000 units and we can fail our + // heuristics. Ensure that no matter what, we can drop + // this node in the tree. + while(!maxSphere.contains(sphere)) + { + maxSphere.setRadius(maxSphere.getRadius() * 2); + } + } + + // if the object's sphere extent (plus one unit) is greater than the maximum size of + // this node sphere times the child scale factor, then the object doesn't "fit" + // in any children. This means it belongs in THIS node. + if((sphere.getRadius() + SphereTreeEpsilon) * leafScaleFactor > maxSphere.getRadius() * childScaleFactor) + { + // this object lives in the contents list + contents.push_back(object); + result = NodeHandle::getNodeHandle(); + result->setObject(object); + result->setNode(this); + + // set real sphere size + const float newSize = (sphere.getCenter() - realSphere.getCenter()).magnitude() + (sphere.getRadius() + SphereTreeEpsilon); + if(newSize > realSphere.getRadius()) + { + resizeRealSphere(newSize); + } + } + else + { + // can recurse to child nodes, find the best child node + typename std::vector::iterator i; + for(i = children.begin(); i != children.end(); ++i) + { + SphereTreeNode * n = (*i); + + // for faster insert times, simply select the + // first available node. If trees become too + // unbalanced and cause performance problems, + // change this code to select the least-loaded + // candidate node. + if(n->canContain(sphere)) + { + candidateNode = n; + break; + } + } + + // no candidate node was identified when looking at the + // child nodes. A new one must be created to hold this + // object + if(! candidateNode) + { + // select the node from the free list (or allocate + // if the free list is empty) + candidateNode = getNode(); + + candidateNode->setParent(this); + + // size the child node's maximum radius relative to + // this node's maximum radius times the childScaleFactor fraction + candidateNode->maxSphere = Sphere(sphere.getCenter(), maxSphere.getRadius() * childScaleFactor); + + // the node only needs to be large enough to hold it's contents. + // keeping it smaller reduces hits when querying the tree + candidateNode->realSphere = Sphere(sphere.getCenter(), sphere.getRadius()); + + children.push_back(candidateNode); + } + + // by this point, if there were no memory allocation problems, + // there is a valid child node to drop the object into. + result = static_cast(candidateNode->addObject(object)); + } + } + return result; +} + +//----------------------------------------------------------------------- + +template +inline const bool SphereTreeNode::canContain(const Sphere & sphere) const +{ + return maxSphere.contains(sphere); +} + +//----------------------------------------------------------------------- + +template +inline const bool SphereTreeNode::canContain(const Vector & point) const +{ + return maxSphere.contains(point); +} + +//----------------------------------------------------------------------- + +template +inline void SphereTreeNode::dumpSphereTreeObjects(std::vector & results) const +{ + typename std::vector::const_iterator c; + for (c = contents.begin(); c != contents.end(); ++c) + results.push_back(*c); + + // recurse to children + typename std::vector::const_iterator s; + for (s = children.begin(); s != children.end(); ++s) + (*s)->dumpSphereTreeObjects(results); +} + +template +inline void SphereTreeNode::dumpSphereTree(std::vector > & results) const +{ + // current node extents + results.push_back(std::pair(0, realSphere)); + results.push_back(std::pair(0, maxSphere)); + + // add content nodes + typename std::vector::const_iterator c; + for(c = contents.begin(); c != contents.end(); ++ c) + { + const Sphere & sphere = getSphere(*c); + results.push_back(std::pair((*c),sphere)); + } + + // recurse to children + // recurse into qualfiying children + typename std::vector::const_iterator s; + for(s = children.begin(); s != children.end(); ++s) + { + (*s)->dumpSphereTree(results); + } +} + +template +inline void SphereTreeNode::dumpSphereTreeNodes(std::vector > & results) const +{ + // current node extents + results.push_back(std::pair(0, realSphere)); + + // recurse to children + // recurse into qualfiying children + typename std::vector::const_iterator s; + for(s = children.begin(); s != children.end(); ++s) + { + (*s)->dumpSphereTreeNodes(results); + } +} + +template +inline void SphereTreeNode::dumpSphereTreeObjs(std::vector > & results) const +{ + // add content nodes + typename std::vector::const_iterator c; + for(c = contents.begin(); c != contents.end(); ++ c) + { + const Sphere & sphere = getSphere(*c); + results.push_back(std::pair((*c),sphere)); + } + + // recurse to children + // recurse into qualfiying children + typename std::vector::const_iterator s; + for(s = children.begin(); s != children.end(); ++s) + { + (*s)->dumpSphereTreeObjs(results); + } +} + +// ---------------------------------------------------------------------- + +template +inline void SphereTreeNode::dumpEdgeList(std::vector & results) const +{ + typename std::vector::const_iterator c; + for(c = contents.begin(); c != contents.end(); ++ c) + { + const Sphere & sphere = getSphere(*c); + + results.push_back(sphere.getCenter()); + results.push_back(realSphere.getCenter()); + } + + /* + if(parent) + { + results.push_back(realSphere.getCenter()); + results.push_back(parent->realSphere.getCenter()); + } + */ + + // recurse to children + typename std::vector::const_iterator s; + for(s = children.begin(); s != children.end(); ++s) + { + (*s)->dumpEdgeList(results); + } +} + +//----------------------------------------------------------------------- + +template +inline void SphereTreeNode::findInRange(const Sphere & range, std::vector & results) const +{ + // check contents + typename std::vector::const_iterator c; + for(c = contents.begin(); c != contents.end(); ++ c) + { + const Sphere & sphere = getSphere(*c); + if(range.intersectsSphere(sphere)) + { + results.push_back((*c)); + } + } + + // recurse into qualfiying children + typename std::vector::const_iterator s; + for(s = children.begin(); s != children.end(); ++s) + { + if(range.contains((*s)->realSphere)) + { + // wholly contained, therefore ALL children + // and ALL contents are satisfied by this + // range query + (*s)->getContents(results); + } + else if(range.intersectsSphere((*s)->realSphere)) + { + // there is a partial intersection with + // a child node, which means some of it's + // children or contents might be out of range. + // each node/item in the child must be checked. + (*s)->findInRange(range, results); + } + } +} + +//----------------------------------------------------------------------- + +template +inline void SphereTreeNode::findInRange(const Sphere & range, std::vector & results, int & testCounter ) const +{ + // check contents + typename std::vector::const_iterator c; + for(c = contents.begin(); c != contents.end(); ++ c) + { + const Sphere & sphere = getSphere(*c); + + testCounter++; + + if(range.intersectsSphere(sphere)) + { + results.push_back((*c)); + } + } + + // recurse into qualfiying children + typename std::vector::const_iterator s; + for(s = children.begin(); s != children.end(); ++s) + { + SphereTreeNode * child = (*s); + + const Sphere & sphere = child->realSphere; + + testCounter++; + + if(range.contains(sphere)) + { + // wholly contained, therefore ALL children + // and ALL contents are satisfied by this + // range query + child->getContents(results); + } + else if(range.intersectsSphere(sphere)) + { + testCounter++; + + // there is a partial intersection with + // a child node, which means some of it's + // children or contents might be out of range. + // each node/item in the child must be checked. + child->findInRange(range, results, testCounter); + } + } +} + +//----------------------------------------------------------------------- + +template +inline void SphereTreeNode::findInRange(const Sphere & range, const SpatialSubdivisionFilter &filter, std::vector & results) const +{ + // check contents + typename std::vector::const_iterator c; + for(c = contents.begin(); c != contents.end(); ++ c) + { + const Sphere & sphere = getSphere(*c); + if(range.intersectsSphere(sphere) && filter(*c)) + { + results.push_back((*c)); + } + } + + // recurse into qualfiying children + typename std::vector::const_iterator s; + for(s = children.begin(); s != children.end(); ++s) + { + if(range.contains((*s)->realSphere)) + { + // wholly contained, therefore ALL children + // and ALL contents are satisfied by this + // range query + (*s)->getContents(filter, results); + } + else if(range.intersectsSphere((*s)->realSphere)) + { + // there is a partial intersection with + // a child node, which means some of it's + // children or contents might be out of range. + // each node/item in the child must be checked. + (*s)->findInRange(range, filter, results); + } + } +} + +// ---------------------------------------------------------------------- + +template +inline void SphereTreeNode::findInRange(const Sphere & range, const SpatialSubdivisionFilter &filter, std::vector & results, int & testCounter) const +{ + // check contents + typename std::vector::const_iterator c; + for(c = contents.begin(); c != contents.end(); ++ c) + { + const Sphere & sphere = getSphere(*c); + + testCounter++; + + if(range.intersectsSphere(sphere) && filter(*c)) + { + results.push_back((*c)); + } + } + + // recurse into qualfiying children + typename std::vector::const_iterator s; + for(s = children.begin(); s != children.end(); ++s) + { + testCounter++; + + if(range.contains((*s)->realSphere)) + { + // wholly contained, therefore ALL children + // and ALL contents are satisfied by this + // range query + (*s)->getContents(filter, results); + } + else if(range.intersectsSphere((*s)->realSphere)) + { + testCounter++; + + // there is a partial intersection with + // a child node, which means some of it's + // children or contents might be out of range. + // each node/item in the child must be checked. + (*s)->findInRange(range, filter, results); + } + } +} + +//----------------------------------------------------------------------- + +template +inline void SphereTreeNode::findOnRay( const Vector & begin, const Vector & dir, std::vector & results) const +{ + // check contents + typename std::vector::const_iterator c; + for(c = contents.begin(); c != contents.end(); ++ c) + { + const Sphere & sphere = getSphere(*c); + + if(sphere.intersectsRay(begin,dir)) + { + results.push_back((*c)); + } + } + + // recurse into qualfiying children + typename std::vector::const_iterator s; + for(s = children.begin(); s != children.end(); ++s) + { + const Sphere & sphere = (*s)->realSphere; + + if(sphere.intersectsRay(begin,dir)) + { + (*s)->findOnRay(begin,dir,results); + } + } +} + +//----------------------------------------------------------------------- + +template +inline void SphereTreeNode::findOnSegment( const Vector & begin, const Vector & end, std::vector & results) const +{ + // check contents + typename std::vector::const_iterator c; + for(c = contents.begin(); c != contents.end(); ++ c) + { + const Sphere & sphere = getSphere(*c); + + if(sphere.intersectsLineSegment(begin,end)) + { + results.push_back((*c)); + } + } + + // recurse into qualfiying children + typename std::vector::const_iterator s; + for(s = children.begin(); s != children.end(); ++s) + { + const Sphere & sphere = (*s)->realSphere; + + if(sphere.intersectsLineSegment(begin,end)) + { + (*s)->findOnSegment(begin,end,results); + } + } +} + +//----------------------------------------------------------------------- + +template +inline void SphereTreeNode::findOnSegment(Vector const & begin, Vector const & end, SpatialSubdivisionFilter const & filter, std::vector & results) const +{ + // check contents + { + typename std::vector::const_iterator c; + for (c = contents.begin(); c != contents.end(); ++ c) + { + if (filter(*c)) + { + Sphere const & sphere = getSphere(*c); + if (sphere.intersectsLineSegment(begin, end)) + results.push_back((*c)); + } + } + } + + // recurse into qualfiying children + { + typename std::vector::const_iterator s; + for (s = children.begin(); s != children.end(); ++s) + { + Sphere const & sphere = (*s)->realSphere; + if (sphere.intersectsLineSegment(begin, end)) + (*s)->findOnSegment(begin, end, results); + } + } +} + +//----------------------------------------------------------------------- + +template +inline void SphereTreeNode::findAtPoint( const Vector & point, std::vector & results) const +{ + // check contents + typename std::vector::const_iterator c; + for(c = contents.begin(); c != contents.end(); ++ c) + { + const Sphere & sphere = getSphere(*c); + + if(sphere.contains(point)) + { + results.push_back((*c)); + } + } + + // recurse into qualfiying children + typename std::vector::const_iterator s; + for(s = children.begin(); s != children.end(); ++s) + { + const Sphere & sphere = (*s)->realSphere; + + if(sphere.contains(point)) + { + (*s)->findAtPoint(point,results); + } + } +} + +// ---------------------------------------------------------------------- + +template +inline void SphereTreeNode::findInRange(const Capsule & range, std::vector & results) const +{ + // check contents + typename std::vector::const_iterator c; + for(c = contents.begin(); c != contents.end(); ++ c) + { + const Sphere & sphere = getSphere(*c); + if(range.intersectsSphere(sphere)) + { + results.push_back((*c)); + } + } + + // recurse into qualfiying children + typename std::vector::const_iterator s; + for(s = children.begin(); s != children.end(); ++s) + { + if(range.contains((*s)->realSphere)) + { + // wholly contained, therefore ALL children + // and ALL contents are satisfied by this + // range query + (*s)->getContents(results); + } + else if(range.intersectsSphere((*s)->realSphere)) + { + // there is a partial intersection with + // a child node, which means some of it's + // children or contents might be out of range. + // each node/item in the child must be checked. + (*s)->findInRange(range, results); + } + } +} + +// ---------------------------------------------------------------------- +template +inline void SphereTreeNode::findInRange(const Capsule & range, SpatialSubdivisionFilter const & filter, std::vector & results) const +{ + // check contents + for (typename std::vector::const_iterator c = contents.begin(); c != contents.end(); ++ c) + if (filter(*c) && range.intersectsSphere(getSphere(*c))) + results.push_back((*c)); + + // recurse into qualfiying children + for (typename std::vector::const_iterator s = children.begin(); s != children.end(); ++s) + { + if (range.contains((*s)->realSphere)) + { + // wholly contained, therefore ALL children + // and ALL contents are satisfied by this + // range query + (*s)->getContents(filter, results); + } + else if (range.intersectsSphere((*s)->realSphere)) + { + // there is a partial intersection with + // a child node, which means some of it's + // children or contents might be out of range. + // each node/item in the child must be checked. + (*s)->findInRange(range, filter, results); + } + } +} +// ---------------------------------------------------------------------- + +template +inline bool SphereTreeNode::findClosest( const Vector & begin, float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance ) const +{ + int dummy = 0; + + return findClosest(begin,maxDistance,outClosest,outMinDistance,outMaxDistance,dummy); +} + +// ---------- + +template +inline bool SphereTreeNode::findClosest( const Vector & begin, float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance, int & testCounter ) const +{ + testCounter++; + + float minDist = realSphere.getCenter().magnitudeBetween(begin) - realSphere.getRadius(); + + if(minDist >= maxDistance) return false; + + if(minDist >= outMinDistance) return false; + + // ---------- + + bool found = false; + + typename std::vector::const_iterator c; + for(c = contents.begin(); c != contents.end(); ++ c) + { + const Sphere & sphere = getSphere(*c); + + testCounter++; + + float dist = sphere.getCenter().magnitudeBetween(begin); + + float minDist = dist - sphere.getRadius(); + float maxDist = dist + sphere.getRadius(); + + if(minDist >= maxDistance) + { + continue; + } + + if(minDist < outMinDistance) + { + found = true; + + outClosest = *c; + outMinDistance = minDist; + outMaxDistance = maxDist; + } + } + + // recurse into qualfiying children + typename std::vector::const_iterator s; + for(s = children.begin(); s != children.end(); ++s) + { + found |= (*s)->findClosest(begin,maxDistance,outClosest,outMinDistance,outMaxDistance,testCounter); + } + + return found; +} + +// ---------------------------------------------------------------------- + +template +inline bool SphereTreeNode::findClosest2d( const Vector & begin, float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance ) const +{ + int dummy = 0; + + return findClosest2d(begin,maxDistance,outClosest,outMinDistance,outMaxDistance,dummy); +} + +// ---------- + +template +inline bool SphereTreeNode::findClosest2d( const Vector & begin, float maxDistance, ObjectType & outClosest, float & outMinDistance, float & outMaxDistance, int & testCounter ) const +{ + testCounter++; + + Vector delta = realSphere.getCenter() - begin; + + delta.y = 0.0f; + + float minDist = delta.magnitude() - realSphere.getRadius(); + + if(minDist >= maxDistance) return false; + + if(minDist >= outMinDistance) return false; + + // ---------- + + bool found = false; + + typename std::vector::const_iterator c; + for(c = contents.begin(); c != contents.end(); ++ c) + { + const Sphere & sphere = getSphere(*c); + + testCounter++; + + Vector delta = sphere.getCenter() - begin; + + delta.y = 0.0f; + + float dist = delta.magnitude(); + + float minDist = dist - sphere.getRadius(); + float maxDist = dist + sphere.getRadius(); + + if(minDist >= maxDistance) + { + continue; + } + + if(minDist < outMinDistance) + { + found = true; + + outClosest = *c; + outMinDistance = minDist; + outMaxDistance = maxDist; + } + } + + // recurse into qualfiying children + typename std::vector::const_iterator s; + for(s = children.begin(); s != children.end(); ++s) + { + found |= (*s)->findClosest2d(begin,maxDistance,outClosest,outMinDistance,outMaxDistance,testCounter); + } + + return found; +} + + +//----------------------------------------------------------------------- + +template +inline void SphereTreeNode::getContents(std::vector & results) +{ + // copy the items from the contents list to the result + // vector + typename std::vector::const_iterator c; + for(c = contents.begin(); c != contents.end(); ++ c) + { + results.push_back((*c)); + } + + // get contents of all children as well + typename std::vector::const_iterator s; + for(s = children.begin(); s != children.end(); ++s) + { + (*s)->getContents(results); + } +} + +//----------------------------------------------------------------------- + +template +inline void SphereTreeNode::getContents(const SpatialSubdivisionFilter &filter, std::vector & results) +{ + // copy the items from the contents list to the result + // vector + typename std::vector::const_iterator c; + for(c = contents.begin(); c != contents.end(); ++ c) + { + if (filter(*c)) + { + results.push_back((*c)); + } + } + + // get contents of all children as well + typename std::vector::const_iterator s; + for(s = children.begin(); s != children.end(); ++s) + { + (*s)->getContents(filter, results); + } +} + +//----------------------------------------------------------------------- + +template +std::vector *> & SphereTreeNode::getNodeFreeList() +{ + // a global sphere tree node free list. Provides constant time + // allocation of nodes if there are any in the list + static VectorPointerPool freeList; + return *(freeList.v); +} + +//----------------------------------------------------------------------- + +template +inline SphereTreeNode * SphereTreeNode::getNode() +{ + SphereTreeNode * result = 0; + + // get a sphere tree node from the free list if it is not empty + // otherwise allocate a new node (which will be put in the free list + // when it is released) + + if(!getNodeFreeList().empty()) + { + result = getNodeFreeList().back(); + result->reinitialize(); + getNodeFreeList().pop_back(); + } + else + { + result = new SphereTreeNode; + } + + return result; +} + +// ---------------------------------------------------------------------- + +template +inline void SphereTreeNode::validate() const +{ + if(!isValidSphere(maxSphere)) + { + DEBUG_FATAL(true,("SphereTreeNode::validate - Node's max sphere is invalid")); + } + + if(!isValidSphere(realSphere)) + { + DEBUG_FATAL(true,("SphereTreeNode::validate - Node's real sphere is invalid")); + } + + if(!maxSphere.contains(realSphere)) + { + DEBUG_FATAL(true,("SphereTreeNode::validate - Node's real sphere is larger than its max sphere\n")); + } + + typename std::vector::const_iterator c; + for(c = contents.begin(); c != contents.end(); ++ c) + { + const Sphere & sphere = getSphere(*c); + + if(!isValidSphere(sphere)) + { + DEBUG_FATAL(true,("SphereTreeNode::validate - Node has a content sphere that's invalid")); + } + + if(!realSphere.contains(sphere)) + { + DEBUG_FATAL(true,("SphereTreeNode::validate - Node doesn't contain all of its contents")); + } + } + + // recurse into qualfiying children + typename std::vector::const_iterator s; + for(s = children.begin(); s != children.end(); ++s) + { + const Sphere & childReal = (*s)->realSphere; + + if(!isValidSphere(childReal)) + { + DEBUG_FATAL(true,("SphereTreeNode::validate - Node has a child sphere that's invalid")); + } + + if(!realSphere.contains(childReal)) + { + DEBUG_FATAL(true,("SphereTreeNode::validate - Node's real sphere doesn't contain its child's real sphere")); + } + + (*s)->validate(); + } +} + +// ---------------------------------------------------------------------- + +template +inline int SphereTreeNode::getNodeCount() const +{ + int accum = 1; + + // recurse into qualfiying children + typename std::vector::const_iterator s; + for(s = children.begin(); s != children.end(); ++s) + { + accum += (*s)->getNodeCount(); + } + + return accum; +} + +// ---------------------------------------------------------------------- + +template +bool SphereTreeNode::empty() const +{ + if (!contents.empty()) + return false; + for (typename std::vector::const_iterator i = children.begin(); i != children.end(); ++i) + if (!(*i)->empty()) + return false; + return true; +} + +// ---------------------------------------------------------------------- + +template +inline int SphereTreeNode::getObjectCount() const +{ + int accum = contents.size(); + + // recurse into qualfiying children + typename std::vector::const_iterator s; + for(s = children.begin(); s != children.end(); ++s) + { + accum += (*s)->getObjectCount(); + } + + return accum; +} + +// ---------------------------------------------------------------------- + +template +inline void SphereTreeNode::apply( typename SphereTreeNode::NodeFunctor N) +{ + N(this); + + // recurse into qualfiying children + typename std::vector::const_iterator s; + for(s = children.begin(); s != children.end(); ++s) + { + (*s)->apply(N); + } +} + +//----------------------------------------------------------------------- +/** @todo potential collision/interaction +*/ +template +inline void SphereTreeNode::move(NodeHandle * handle) +{ + const Sphere & sphere = getSphere(handle->getObject()); + + if(!isValidSphere(sphere)) + { + WARNING_STRICT_FATAL(true, ("SphereTreeNode::move - sphere for the object being moved is invalid.")); + + return; + } + + // if this node cannot contain the update sphere, + // perform sizeing or reintegration + if(!realSphere.contains(sphere)) + { + if(!maxSphere.contains(sphere)) + { + // remove the object from this node + typename std::vector::iterator i; + ObjectType o = handle->getObject(); + i = std::find(contents.begin(), contents.end(), o); + if(i != contents.end()) + { + *i = contents.back(); + contents.pop_back(); + } + + // reintergrate object in tree + handle->setNode(0); + + if(parent) + parent->relocateObject(handle, sphere); + else + relocateObject(handle, sphere); + + if(contents.empty() && children.empty()) + { + // this node disappears + if(parent) + { + parent->unlinkNode(this); + } + } + + + } + else + { + // resize the real sphere + const float newSize = (sphere.getCenter() - realSphere.getCenter()).magnitude() + (sphere.getRadius() + SphereTreeEpsilon); + if(newSize > realSphere.getRadius()) + { + resizeRealSphere(newSize); + } + } + } +} + +//----------------------------------------------------------------------- + +template +inline void SphereTreeNode::relocateObject(NodeHandle * handle, const Sphere & sphere) +{ + if(!maxSphere.contains(sphere)) + { + // this node can not contain the sphere, pass it to the parent + // node + if(parent) + { + parent->relocateObject(handle, sphere); + } + else + { + // this is the root node, resize the root node because it + // ALWAYS can contain an object. + if(sphere.getRadius() * leafScaleFactor > maxSphere.getRadius()) + { + maxSphere.setRadius(sphere.getRadius() * leafScaleFactor); + } + + // dirty hack.. floating point error becomes intolerable + // at distances over 16000 units and we can fail our + // heuristics. Ensure that no matter what, we can drop + // this node in the tree. + while(!maxSphere.contains(sphere)) + { + maxSphere.setRadius(maxSphere.getRadius() * 2); + } + + // it should not fail the relocation test now. + relocateObject(handle, sphere); + } + } + else + { + // find a child node + if((sphere.getRadius() + SphereTreeEpsilon) * leafScaleFactor > maxSphere.getRadius() * childScaleFactor) + { + // this object lives in the contents list + contents.push_back(handle->getObject()); + handle->setNode(this); + + // set real sphere size + const float newSize = (sphere.getCenter() - realSphere.getCenter()).magnitude() + sphere.getRadius() + SphereTreeEpsilon; + if(newSize > realSphere.getRadius()) + { + resizeRealSphere(newSize); + } + } + else + { + // can recurse to child nodes + SphereTreeNode * candidateNode = 0; + typename std::vector::iterator i; + for(i = children.begin(); i != children.end(); ++i) + { + SphereTreeNode * n = (*i); + if(n->canContain(sphere)) + { + candidateNode = n; + break; + } + } + + if(! candidateNode) + { + candidateNode = getNode(); + candidateNode->setParent(this); + candidateNode->maxSphere = Sphere(sphere.getCenter(), maxSphere.getRadius() * childScaleFactor); + candidateNode->realSphere = Sphere(sphere.getCenter(), sphere.getRadius()); + children.push_back(candidateNode); + } + candidateNode->relocateObject(handle, sphere); + } + } +} + +//----------------------------------------------------------------------- + +template +inline void SphereTreeNode::releaseNode(SphereTreeNode * node) +{ + // delete child nodes + typename std::vector::iterator i; + for(i = node->children.begin(); i != node->children.end(); ++i) + { + SphereTreeNode * c = (*i); + releaseNode(c); + } + node->children.clear(); + + node->parent = 0; + node->contents.clear(); + + getNodeFreeList().push_back(node); +} + +//----------------------------------------------------------------------- + +template +inline void SphereTreeNode::removeObject(NodeHandle * handle) +{ + // find in contents + // remove the object from this node + typename std::vector::iterator i; + ObjectType o = handle->getObject(); + i = std::find(contents.begin(), contents.end(), o); + if(i != contents.end()) + { + *i = contents.back(); + contents.pop_back(); + } + + if(contents.empty() && children.empty()) + { + // this node disappears + if(parent) + { + parent->unlinkNode(this); + } + } + handle->setNode(0); + +} + +//----------------------------------------------------------------------- + +template +inline void SphereTreeNode::internalResizeRealSphere(const float newRadius) +{ + // if a realSphere resizes, that may affect the parent node's real + // size as well. Ensure that the parent/child relationship is + // maintained when resizing + realSphere.setRadius(newRadius); + if(parent) + { + if(! parent->realSphere.contains(realSphere)) + { + // the parent cannot contain the new realSphere unless its + // real sphere is resized + const float upRadius = realSphere.getCenter().magnitudeBetween(parent->realSphere.getCenter()) + newRadius; + + float actualRadius = std::max(parent->realSphere.getRadius(), upRadius) + 0.1f; + + parent->internalResizeRealSphere(actualRadius); + } + } + else + { + maxSphere = Sphere( realSphere.getCenter(), realSphere.getRadius() + 0.1f ); + } +} + +//----------------------------------------------------------------------- + +template +inline void SphereTreeNode::resizeRealSphere(const float newRadius) +{ + internalResizeRealSphere (newRadius); + +#if _DEBUG + if(parent && !parent->realSphere.contains(realSphere)) + { + Vector A = parent->realSphere.getCenter(); + float AR = parent->realSphere.getRadius(); + + Vector B = realSphere.getCenter(); + float BR = realSphere.getRadius(); + + float D = A.magnitudeBetween(B); + float O = abs(AR - (D + BR)); + + // Fatal if the error is significant, otherwise just warn. + + if(O > 0.1f) + { + DEBUG_FATAL(true,("Sphere tree node isn't contained by its parent node.\n Parent (%f,%f,%f - %f), Child (%f,%f,%f - %f), distance %f, error %f\n",A.x,A.y,A.z,AR,B.x,B.y,B.z,BR,D,O)); + } + else + { + DEBUG_WARNING(true,("Sphere tree node isn't contained by its parent node.\n Parent (%f,%f,%f - %f), Child (%f,%f,%f - %f), distance %f, error %f\n",A.x,A.y,A.z,AR,B.x,B.y,B.z,BR,D,O)); + } + } +#endif +} + +//----------------------------------------------------------------------- + +template +inline void SphereTreeNode::unlinkNode(SphereTreeNode * node) +{ + // find the child node to be unlinked, then release it to the node + // free list. + typename std::vector::iterator i; + i = std::find(children.begin(), children.end(), node); + if(i != children.end()) + { + releaseNode(node); + *i = children.back(); + children.pop_back(); + } + + // am I empty now? + if(contents.empty()) + { + if(children.empty()) + { + if(parent) + { + // advise the parent that this node is going awawy. That + // may cause the parent to be empty as well, so it in turn + // should be unlinked + parent->unlinkNode(this); + } + } + } +} + +// ---------------------------------------------------------------------- + +template +inline SphereTreeNode * SphereTreeNode::getParent() +{ + return parent; +} + +template +inline SphereTreeNode const * SphereTreeNode::getParent() const +{ + return parent; +} + +template +inline void SphereTreeNode::setParent(SphereTreeNode * newParent) +{ + // Make sure we're not making this node an ancestor of itself + +#ifdef _DEBUG + + SphereTreeNode * cursor = newParent; + + while(cursor) + { + DEBUG_FATAL(cursor == this,("SphereTreeNode::setParent - Trying to make a node an ancestor of itself\n")); + + cursor = cursor->parent; + } + +#endif + + parent = newParent; +} + +// ---------------------------------------------------------------------- + +template +inline Sphere SphereTreeNode::getSphere(ObjectType object) const +{ + Sphere temp = ExtentAccessor::getExtent(object); + + if(temp.getRadius() < 0.5f) + { + // HACK insure a minimum radius so that zero-sized or very small objects don't + // cause the sphere tree to get too deep + temp.setRadius(0.5f); + } + + return temp; +} + +// ---------------------------------------------------------------------- + +#if defined(PLATFORM_WIN32) + +#include + +template +inline bool SphereTreeNode::isValidSphere(Sphere const & sphere) const +{ + Vector const & center = sphere.getCenter(); + float radius = sphere.getRadius(); + + if(_isnan(center.x)) return false; + if(_isnan(center.y)) return false; + if(_isnan(center.z)) return false; + if(_isnan(radius)) return false; + + if(!_finite(center.x)) return false; + if(!_finite(center.y)) return false; + if(!_finite(center.z)) return false; + if(!_finite(radius)) return false; + + return true; +} + +// ---------- + +#elif defined(PLATFORM_LINUX) + +#include + +template +inline bool SphereTreeNode::isValidSphere(Sphere const & sphere) const +{ + Vector const & center = sphere.getCenter(); + float radius = sphere.getRadius(); + + if(isnan(center.x)) return false; + if(isnan(center.y)) return false; + if(isnan(center.z)) return false; + if(isnan(radius)) return false; + + if(!finite(center.x)) return false; + if(!finite(center.y)) return false; + if(!finite(center.z)) return false; + if(!finite(radius)) return false; + + return true; +} + +// ---------- + +#else + +#error unsupported platform + +#endif + +//----------------------------------------------------------------------- + +template +inline bool SphereTreeNode::isWithin (Vector const & position) const +{ + if (!canContain (position)) + return false; + + //-- search content nodes + { + typename std::vector::const_iterator iter; + for (iter = contents.begin (); iter != contents.end (); ++iter) + { + Sphere const & sphere = getSphere (*iter); + if (sphere.contains (position)) + return true; + } + } + + //-- search children + { + typename std::vector::const_iterator iter; + for (iter = children.begin(); iter != children.end(); ++iter) + { + SphereTreeNode const * const node = *iter; + if (node->isWithin (position)) + return true; + } + } + + return false; +} + +//----------------------------------------------------------------------- + +template +Sphere const &SphereTreeNode::getRealSphere() const +{ + return realSphere; +} + +//----------------------------------------------------------------------- + +template +class BaseSphereTreeAccessor +{ +public: + static typename SphereTreeNode::NodeHandle *allocateNodeHandle() + { + return new typename SphereTreeNode::NodeHandle; + } +}; + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_SphereTreeNode_H diff --git a/engine/shared/library/sharedMath/src/shared/Transform.cpp b/engine/shared/library/sharedMath/src/shared/Transform.cpp new file mode 100644 index 00000000..9cc8c181 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/Transform.cpp @@ -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 + +// ====================================================================== + +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(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; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedMath/src/shared/Transform.h b/engine/shared/library/sharedMath/src/shared/Transform.h new file mode 100644 index 00000000..f3e7d78a --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/Transform.h @@ -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 diff --git a/engine/shared/library/sharedMath/src/shared/Transform2d.cpp b/engine/shared/library/sharedMath/src/shared/Transform2d.cpp new file mode 100644 index 00000000..045064b9 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/Transform2d.cpp @@ -0,0 +1,118 @@ +//=================================================================== +// +// Transform2d.cpp +// asommers +// +// copyright 2002, sony online entertainment +// +//=================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/Transform2d.h" +#include "sharedMath/Rectangle2d.h" + +//=================================================================== + +const Transform2d Transform2d::identity; + +//=================================================================== + +//------------------------------------------------------------------- + +void Transform2d::yaw_l (float radians) +{ + const float sine = sin (radians); + const float cosine = cos (radians); + const float a = m_matrix [0][0]; + const float b = m_matrix [0][1]; + const float c = m_matrix [1][0]; + const float d = m_matrix [1][1]; + + m_matrix [0][0] = a * cosine + b * -sine; + m_matrix [0][1] = a * sine + b * cosine; + + m_matrix [1][0] = c * cosine + d * -sine; + m_matrix [1][1] = c * sine + d * cosine; +} + +//------------------------------------------------------------------- + +void Transform2d::rotateTranslate_p2l(Rectangle2d &o_result, const Rectangle2d &r) const +{ + const float x0 = r.x0 - m_matrix[0][2]; + const float y0 = r.y0 - m_matrix[1][2]; + const float x1 = r.x1 - m_matrix[0][2]; + const float y1 = r.y1 - m_matrix[1][2]; + + float tx0, tx1, ty0, ty1; + + //------------------------- + // calculate max and min x + tx0=m_matrix[0][0]*x0; + tx1=m_matrix[0][0]*x1; + ty0=m_matrix[1][0]*y0; + ty1=m_matrix[1][0]*y1; + if (tx1>=tx0) + { + if (ty1>=ty0) + { + o_result.x1=tx1+ty1; + o_result.x0=tx0+ty0; + } + else + { + o_result.x1=tx1+ty0; + o_result.x0=tx0+ty1; + } + } + else + { + if (ty1>=ty0) + { + o_result.x1=tx0+ty1; + o_result.x0=tx1+ty0; + } + else + { + o_result.x1=tx0+ty0; + o_result.x0=tx1+ty1; + } + } + //------------------------- + + //------------------------- + // calculate max and min y + tx0=m_matrix[0][1]*x0; + tx1=m_matrix[0][1]*x1; + ty0=m_matrix[1][1]*y0; + ty1=m_matrix[1][1]*y1; + if (tx1>=tx0) + { + if (ty1>=ty0) + { + o_result.y1=tx1+ty1; + o_result.y0=tx0+ty0; + } + else + { + o_result.y1=tx1+ty0; + o_result.y0=tx0+ty1; + } + } + else + { + if (ty1>=ty0) + { + o_result.y1=tx0+ty1; + o_result.y0=tx1+ty0; + } + else + { + o_result.y1=tx0+ty0; + o_result.y0=tx1+ty1; + } + } + //------------------------- +} + +//------------------------------------------------------------------- diff --git a/engine/shared/library/sharedMath/src/shared/Transform2d.h b/engine/shared/library/sharedMath/src/shared/Transform2d.h new file mode 100644 index 00000000..9266b375 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/Transform2d.h @@ -0,0 +1,171 @@ +//=================================================================== +// +// Transform2d.h +// asommers +// +// copyright 2002, sony online entertainment +// +//=================================================================== + +#ifndef INCLUDED_Transform2d_H +#define INCLUDED_Transform2d_H + +//=================================================================== + +#include "sharedMath/Vector2d.h" + +//=================================================================== + +class Rectangle2d; + +//=================================================================== + +class Transform2d +{ +public: + + static const Transform2d identity; + +public: + + Transform2d (); + + void move_l (const Vector2d& v); + void move_p (const Vector2d& v); + + void yaw_l (float radians); + void resetRotate_l2p (); + void resetRotateTranslate_l2p (); + + const Vector2d getPosition_p () const; + void setPosition_p (const Vector2d& v); + void setPosition_p (float x, float y); + + const Vector2d rotate_l2p (const Vector2d& v) const; + const Vector2d rotateTranslate_l2p (const Vector2d& v) const; + const Vector2d rotate_p2l (const Vector2d& v) const; + const Vector2d rotateTranslate_p2l (const Vector2d& v) const; + + //---------------------------------------------------------------------------- + // Returns the result equivalent to expanding the source rectangle into its + // four corner points, transform each four points using rotateTranslate_p2l, + // and then finding the resulting bounding rectangle of those four points. + // 'r' and 'o_result' may reference the same object. + void rotateTranslate_p2l(Rectangle2d &o_result, const Rectangle2d &r) const; + //---------------------------------------------------------------------------- + + bool operator== (const Transform2d& rhs) const; + bool operator!= (const Transform2d& rhs) const; + +private: + + float m_matrix [2][3]; +}; + +//------------------------------------------------------------------- + +inline void Transform2d::resetRotateTranslate_l2p () +{ + // make the diagonal 1's to form the identity m_matrix + m_matrix [0][0] = 1.f; + m_matrix [0][1] = 0.f; + m_matrix [0][2] = 0.f; + + m_matrix [1][0] = 0.f; + m_matrix [1][1] = 1.f; + m_matrix [1][2] = 0.f; +} + +//------------------------------------------------------------------- + +inline void Transform2d::resetRotate_l2p () +{ + m_matrix [0][0] = 1.f; + m_matrix [0][1] = 0.f; + + m_matrix [1][0] = 0.f; + m_matrix [1][1] = 1.f; +} + +//------------------------------------------------------------------- + +inline Transform2d::Transform2d () +{ + resetRotateTranslate_l2p (); +} + +//------------------------------------------------------------------- + +inline void Transform2d::move_p (const Vector2d& v) +{ + m_matrix [0][2] += v.x; + m_matrix [1][2] += v.y; +} + +//------------------------------------------------------------------- + +inline void Transform2d::move_l (const Vector2d& v) +{ + move_p (rotate_l2p (v)); +} + +//------------------------------------------------------------------- + +inline const Vector2d Transform2d::getPosition_p () const +{ + return Vector2d (m_matrix [0][2], m_matrix [1][2]); +} + +//------------------------------------------------------------------- + +inline void Transform2d::setPosition_p (const Vector2d& v) +{ + m_matrix [0][2] = v.x; + m_matrix [1][2] = v.y; +} + +//------------------------------------------------------------------- + +inline void Transform2d::setPosition_p (float x, float y) +{ + m_matrix [0][2] = x; + m_matrix [1][2] = y; +} + +//------------------------------------------------------------------- + +inline const Vector2d Transform2d::rotate_l2p (const Vector2d& v) const +{ + return Vector2d (m_matrix [0][0] * v.x + m_matrix [0][1] * v.y, m_matrix [1][0] * v.x + m_matrix [1][1] * v.y); +} + +//------------------------------------------------------------------- + +inline const Vector2d Transform2d::rotateTranslate_l2p (const Vector2d& v) const +{ + return Vector2d (m_matrix [0][0] * v.x + m_matrix [0][1] * v.y + m_matrix [0][2], m_matrix [1][0] * v.x + m_matrix [1][1] * v.y + m_matrix [1][2]); +} + +//------------------------------------------------------------------- + +inline const Vector2d Transform2d::rotate_p2l (const Vector2d& v) const +{ + return Vector2d (m_matrix [0][0] * v.x + m_matrix [1][0] * v.y, m_matrix [0][1] * v.x + m_matrix [1][1] * v.y); +} + +//------------------------------------------------------------------- + +inline const Vector2d Transform2d::rotateTranslate_p2l (const Vector2d& v) const +{ + const float x = v.x - m_matrix[0][2]; + const float y = v.y - m_matrix[1][2]; + + return Vector2d( + m_matrix[0][0]*x + m_matrix[1][0]*y, + m_matrix[0][1]*x + m_matrix[1][1]*y + ); +} + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedMath/src/shared/Vector.cpp b/engine/shared/library/sharedMath/src/shared/Vector.cpp new file mode 100644 index 00000000..341cfed8 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/Vector.cpp @@ -0,0 +1,321 @@ +// ====================================================================== +// +// Vector.cpp +// Portions copyright 1998 Bootprint Entertainment. +// Portions copyright 2000-2001 Sony Online Entertainment. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/Vector.h" + +#include "sharedRandom/Random.h" + +#include + +// ====================================================================== + +const Vector Vector::unitX(CONST_REAL(1), CONST_REAL(0), CONST_REAL(0)); +const Vector Vector::unitY(CONST_REAL(0), CONST_REAL(1), CONST_REAL(0)); +const Vector Vector::unitZ(CONST_REAL(0), CONST_REAL(0), CONST_REAL(1)); + +const Vector Vector::negativeUnitX(CONST_REAL(-1), CONST_REAL( 0), CONST_REAL( 0)); +const Vector Vector::negativeUnitY(CONST_REAL( 0), CONST_REAL(-1), CONST_REAL( 0)); +const Vector Vector::negativeUnitZ(CONST_REAL( 0), CONST_REAL( 0), CONST_REAL(-1)); + +const Vector Vector::zero(CONST_REAL(0), CONST_REAL(0), CONST_REAL(0)); +const Vector Vector::xyz111(CONST_REAL(1), CONST_REAL(1), CONST_REAL(1)); + +const Vector Vector::maxXYZ(REAL_MAX, REAL_MAX, REAL_MAX); +const Vector Vector::negativeMaxXYZ(-REAL_MAX, -REAL_MAX, -REAL_MAX); + +const real Vector::NORMALIZE_THRESHOLD(CONST_REAL(0.00001)); + +const real Vector::NORMALIZED_EPSILON(CONST_REAL(0.00001)); + +// If M is between 1-e and 1+e, then M^2 is between 1-2e+e^2 and 1+2e+e^2. + +static const real NORMALIZED_RANGE_SQUARED_MIN = (1.0f - (2.0f * Vector::NORMALIZED_EPSILON)) + (Vector::NORMALIZED_EPSILON * Vector::NORMALIZED_EPSILON); +static const real NORMALIZED_RANGE_SQUARED_MAX = (1.0f + (2.0f * Vector::NORMALIZED_EPSILON)) + (Vector::NORMALIZED_EPSILON * Vector::NORMALIZED_EPSILON); + +// ====================================================================== +// Normalize a vector to a length of 1 +// +// Return value: +// +// True if the vector has been normalized, otherwise false. +// +// Remarks: +// +// If the vector is too small, it cannot be normalized. + +bool Vector::normalize(void) +{ + real mag = magnitude(); + + if (mag < NORMALIZE_THRESHOLD) + return false; + + *this /= mag; + + return true; +} + +// ---------------------------------------------------------------------- +/** + * Normalize a vector to a length of approximately 1. + * + * If the vector is too small, it cannot be normalized. + * + * @return True if the vector has been approximately normalized, otherwise false. + */ + +bool Vector::approximateNormalize(void) +{ + real mag = approximateMagnitude(); + + if (mag < NORMALIZE_THRESHOLD) + return false; + + *this /= mag; + + return true; +} + +// ---------------------------------------------------------------------- +/** + * Return true if a vector is of length 1 (within some tolerance) + * + * Vectors normalized with Vector::normalize() should always be of unit + * length within tolerance, vectors normalized with Vector::approximate + * Normalize will not. + * + * @return True if the vector's length is within NORMALIZED_TOLERANCE of 1 + */ + +bool Vector::isNormalized(void) const +{ + real mag2 = magnitudeSquared(); + + return WithinRangeInclusiveInclusive(NORMALIZED_RANGE_SQUARED_MIN,mag2,NORMALIZED_RANGE_SQUARED_MAX); +} + +// ---------------------------------------------------------------------- +/** + * Find the point on the specified line that is as close to this point as possible. + * + * The line is treated as an infinite line, not a line segment. + * + * @param line0 First point on the line + * @param line1 Second point on the line + * @param t Parameteric time along the line that is closest to this vector + */ + +const Vector Vector::findClosestPointOnLine(const Vector &line0, const Vector &line1, real *t) const +{ + DEBUG_FATAL(!t, ("t arg is null")); + + NOT_NULL(t); + + Vector delta(line1 - line0); + const real r = (*this - line0).dot(delta) / delta.magnitudeSquared(); + *t = r; + return line0 + delta * r; +} + +// ---------------------------------------------------------------------- +/** + * Find the point on the specified line that is as close to this point as possible. + * + * The line is treated as an infinite line, not a line segment. + * + * @param line0 First point on the line + * @param line1 Second point on the line + */ + +const Vector Vector::findClosestPointOnLine(const Vector &line0, const Vector &line1) const +{ + real t; + return findClosestPointOnLine(line0, line1, &t); +} + +//----------------------------------------------------------------------- + +const Vector Vector::findClosestPointOnLineSegment(const Vector & startPoint, const Vector & endPoint) const +{ + Vector delta(endPoint - startPoint); + + // if these vectors describe a point instead of a line-segment, return the startpoint + // rather than returning an invalid vector + const real deltaMagnitudeSquared = delta.magnitudeSquared(); + if(deltaMagnitudeSquared = 0.0f; + } +} + +bool Vector::inPolygon (const Vector& v0, const Vector& v1, const Vector& v2) const +{ + return sameSide(*this, v0, v1, v2) && sameSide(*this, v1, v2, v0) && sameSide(*this, v2, v0, v1); +} + +// ---------------------------------------------------------------------- +/** + * Test whether a point lies within a convex n-sided polygon. + * + * This should be on at least the plane for the test to work. See Plane::findIntersection () + */ + +bool Vector::inPolygon(const std::vector &convexPolygonVertices) const +{ + // @todo optimize this + const uint numberOfConvexPolygonVertices = convexPolygonVertices.size(); + for (uint i = 1; i < numberOfConvexPolygonVertices-1; ++i) + if (inPolygon(convexPolygonVertices[0], convexPolygonVertices[i], convexPolygonVertices[i+1])) + return true; + + return false; +} + +// ---------------------------------------------------------------------- +/** + * Determine if two vectors are within an epsilon distance. + * The epsilon distance is tested for all three dimensions, not a + * distance between the points. + * + * @param rhs The second vector to compare. + * @param epsilon The epsilon distance. + */ +bool Vector::withinEpsilon(const Vector &rhs, float epsilon) const +{ + return (abs(x - rhs.x) < epsilon) && (abs(y - rhs.y) < epsilon) && (abs(z - rhs.z) < epsilon); +} + + +// ---------------------------------------------------------------------- +/** + * Find a direction which is perpendicular to the vector passed in. + * NOTE: The result is NOT guaranteed to be normalized. + */ + +const Vector Vector::perpendicular(Vector const & direction) +{ + // Measure the projection of "direction" onto each of the axes + float const id = abs(direction.dot(Vector::unitX)); + float const jd = abs(direction.dot(Vector::unitY)); + float const kd = abs(direction.dot(Vector::unitZ)); + + Vector result; + + if (id <= jd && id <= kd) + // Projection onto i was the smallest + result = direction.cross(Vector::unitX); + else if (jd <= id && jd <= kd) + // Projection onto j was the smallest + result = direction.cross(Vector::unitY); + else + // Projection onto k was the smallest + result = direction.cross(Vector::unitZ); + + result.normalize(); + + return result; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedMath/src/shared/Vector.h b/engine/shared/library/sharedMath/src/shared/Vector.h new file mode 100644 index 00000000..ceda3509 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/Vector.h @@ -0,0 +1,716 @@ +// ====================================================================== +// +// Vector.h +// Portions copyright 1998 Bootprint Entertainment. +// Portions copyright 2000-2001 Sony Online Entertainment. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_Vector_H +#define INCLUDED_Vector_H + +// ====================================================================== + +class Vector +{ +public: + + // Vector 1,0,0 + static const Vector unitX; + + // Vector 0,1,0 + static const Vector unitY; + + // Vector 0,0,1 + static const Vector unitZ; + + // Vector -1,0,0 + static const Vector negativeUnitX; + + // Vector 0,-1,0 + static const Vector negativeUnitY; + + // Vector 0,0,-1 + static const Vector negativeUnitZ; + + // Vector 0,0,0 + static const Vector zero; + + // Vector 1,1,1 + static const Vector xyz111; + + // Vector max, max, max + static const Vector maxXYZ; + + // Vector -maxXYZ + static const Vector negativeMaxXYZ; + + // minimum vector magnitude to normalize + static const real NORMALIZE_THRESHOLD; + + // A vector is normalized if its magnitude is within NORMALIZED_EPSILON of 1. + static const real NORMALIZED_EPSILON; + +public: + + // x-component of the 3d vector + real x; //lint !e1925 // Public data member + + // y-component of the 3d vector + real y; //lint !e1925 // Public data member + + // z-component of the 3d vector + real z; //lint !e1925 // Public data member + +public: + + Vector(void); + Vector(real newX, real newY, real newZ); + + void debugPrint(const char *header) const; + + void set(real newX, real newY, real newZ); + void makeZero(void); + + bool normalize(void); + bool approximateNormalize(void); + bool isNormalized(void) const; + + const Vector findClosestPointOnLine(const Vector &line0, const Vector &line1) const; + const Vector findClosestPointOnLine(const Vector &line0, const Vector &line1, real *t) const; + const Vector findClosestPointOnLineSegment(const Vector & startPoint, const Vector & endPoint) const; + real distanceToLine(const Vector &line0, const Vector &line1) const; + real distanceToLineSegment(const Vector &line0, const Vector &line1) const; + + real theta(void) const; + real phi(void) const; + + real dot(const Vector &vector) const; + const Vector cross(const Vector &rhs) const; + + real magnitudeSquared(void) const; + real approximateMagnitude(void) const; + real magnitude(void) const; + real magnitudeBetween(const Vector &vector) const; + real magnitudeBetweenSquared(const Vector &vector) const; + real magnitudeXYBetween(const Vector &vector) const; + real magnitudeXYBetweenSquared(const Vector &vector) const; + real magnitudeXZBetween(const Vector &vector) const; + real magnitudeXZBetweenSquared(const Vector &vector) const; + real magnitudeYZBetween(const Vector &vector) const; + real magnitudeYZBetweenSquared(const Vector &vector) const; + + const Vector operator -(void) const; + + Vector &operator -=(const Vector &rhs); + Vector &operator +=(const Vector &rhs); + Vector &operator /=(real scalar); + Vector &operator *=(real scalar); + + const Vector operator +(const Vector &rhs) const; + const Vector operator -(const Vector &rhs) const; + const Vector operator *(real scalar) const; + const Vector operator /(real scalar) const; + friend const Vector operator *(real scalar, const Vector &vector); + + bool operator ==(const Vector &rhs) const; + bool operator !=(const Vector &rhs) const; + bool withinEpsilon(const Vector &rhs, float epsilon) const; + + const Vector reflectIncoming(const Vector &incident) const; + const Vector reflectOutgoing(const Vector &incident) const; + + // const Vector refract(const Vector &normal, real n1, real n2); + + bool inPolygon (const Vector& v0, const Vector& v1, const Vector& v2) const; + bool inPolygon (const stdvector::fwd &convexPolygonVertices) const; + +public: + + static const Vector midpoint(const Vector &vector1, const Vector &vector2); + static const Vector linearInterpolate(const Vector &begin, const Vector &end, real t); + + static const Vector randomUnit(void); + static const Vector randomCube(real halfSideLength=CONST_REAL(1)); + + static const Vector perpendicular(Vector const & direction); +}; + +// ====================================================================== +// Construct a vector +// +// Remarks: +// +// Initializes the components to 0. + +inline Vector::Vector(void) +: x(CONST_REAL(0)), y(CONST_REAL(0)), z(CONST_REAL(0)) +{ +} + +// ---------------------------------------------------------------------- +/** + * Construct a vector. + * + * Initializes the components to the specified values + * + * @param newX Value for the X component + * @param newY Value for the Y component + * @param newZ Value for the Z component + */ + +inline Vector::Vector(real newX, real newY, real newZ) +: x(newX), y(newY), z(newZ) +{ +} + +// ---------------------------------------------------------------------- +/** + * Set the vector components to new values. + * + * @param newX Value for the X component + * @param newY Value for the Y component + * @param newZ Value for the Z component + */ + +inline void Vector::set(real newX, real newY, real newZ) +{ + x = newX; + y = newY; + z = newZ; +} + +// ---------------------------------------------------------------------- +/** + * Set all the vector components to zero. + */ + +inline void Vector::makeZero(void) +{ + x = CONST_REAL(0); + y = CONST_REAL(0); + z = CONST_REAL(0); +} + +// ---------------------------------------------------------------------- +/** + * Return the rotation of the vector around the Y plane. + * + * The result is undefined if both the x and z values of the vector are zero. + * + * This routine uses atan2() so it is not particularly fast. + * + * @return The rotation of the vector around the Y plane + */ + +inline real Vector::theta(void) const +{ + return atan2(x, z); +} + +// ---------------------------------------------------------------------- +/** + * Calculate the angle of the vector from the X-Z plane. + * + * This routine uses sqrt() and atan2() so it is not particularly fast. + * + * @return The angle of the vector from the X-Z plane + */ + +inline real Vector::phi(void) const +{ + return atan2(-y, sqrt(sqr(x) + sqr(z))); +} + +// ---------------------------------------------------------------------- +/** + * Compute the dot product between this vector and another vector. + * + * The dot product value is equal to the cosine of the angle between + * the two vectors multiplied by the sum of the lengths of the vectors. + * + * @param vector Vector to compute the dot product against + */ + +inline real Vector::dot(const Vector &vec) const +{ + return (x * vec.x) + (y * vec.y) + (z * vec.z); +} + +// ---------------------------------------------------------------------- +/** + * Calculate the square of the magnitude of this vector. + * + * This routine is much faster than magnitude(). + * + * @return The square of the magnitude of the vector + * @see Vector::magnitude() + */ + +inline real Vector::magnitudeSquared(void) const +{ + return (sqr(x) + sqr(y) + sqr(z)); +} + +// ---------------------------------------------------------------------- +/** + * Calculate the approximate magnitude of this vector. + * + * The implementation of this routine has +/- 8% error. + * + * @return The approximate magnitude of the vector + */ + + +inline real Vector::approximateMagnitude(void) const +{ + real minc = abs(x); + real midc = abs(y); + real maxc = abs(z); + + // sort the vectors + // we do our own swapping to avoid heavy-weight includes in such a low-level class + if (midc < minc) + { + const real temp = midc; + midc = minc; + minc = temp; + } + + if (maxc < minc) + { + const real temp = maxc; + maxc = minc; + minc = temp; + } + + if (maxc < midc) + { + const real temp = maxc; + maxc = midc; + midc = temp; + } + + return (maxc + CONST_REAL(11.0f / 32.0f) * midc + CONST_REAL(0.25f) * minc); +} + +// ---------------------------------------------------------------------- +/** + * Calculate the magnitude of this vector. + * + * This routine is slow because it requires a square root operation. + * + * @return The magnitude of the vector + * @see Vector::magnitudeSquared() + */ + +inline real Vector::magnitude(void) const +{ + return sqrt(magnitudeSquared()); +} + +// ---------------------------------------------------------------------- +/** + * Calculate the square of the magnitude of the vector between this vector and the specified vector. + * + * This routine is much faster than magnitudeBetween(). + * + * @param vector The other endpoint of the delta vector + * @return The square of the magnitude of the delta vector + * @see Vector::magnitudeBetween() + */ + +inline real Vector::magnitudeBetweenSquared(const Vector &vec) const +{ + return (sqr(x - vec.x) + sqr(y - vec.y) + sqr(z - vec.z)); +} + +// ---------------------------------------------------------------------- +/** + * Calculate the magnitude of the vector between this vector and the specified vector. + * + * This routine is much slower than magnitudeBetweenSquared(). + * + * @param vector The other endpoint of the delta vector + * @return The magnitude of the delta vector + * @see Vector::magnitudeBetweenSquared() + */ + +inline real Vector::magnitudeBetween(const Vector &vec) const +{ + return sqrt(magnitudeBetweenSquared(vec)); +} + +// ---------------------------------------------------------------------- +/** +* Calculate the square of the magnitude of the vector between this vector and the specified vector. +* +* This routine is much faster than magnitudeBetween(). +* +* @param vector The other endpoint of the delta vector +* @return The square of the magnitude of the delta vector +* @see Vector::magnitudeBetween() +*/ + +inline real Vector::magnitudeXYBetweenSquared(const Vector &vec) const +{ + return (sqr(x - vec.x) + sqr(y - vec.y)); +} + +// ---------------------------------------------------------------------- +/** +* Calculate the magnitude of the vector between this vector and the specified vector. +* +* This routine is much slower than magnitudeBetweenSquared(). +* +* @param vector The other endpoint of the delta vector +* @return The magnitude of the delta vector +* @see Vector::magnitudeBetweenSquared() +*/ + +inline real Vector::magnitudeXYBetween(const Vector &vec) const +{ + return sqrt(magnitudeXYBetweenSquared(vec)); +} + +// ---------------------------------------------------------------------- +/** +* Calculate the square of the magnitude of the vector between this vector and the specified vector. +* +* This routine is much faster than magnitudeBetween(). +* +* @param vector The other endpoint of the delta vector +* @return The square of the magnitude of the delta vector +* @see Vector::magnitudeBetween() +*/ + +inline real Vector::magnitudeXZBetweenSquared(const Vector &vec) const +{ + return (sqr(x - vec.x) + sqr(z - vec.z)); +} + +// ---------------------------------------------------------------------- +/** +* Calculate the magnitude of the vector between this vector and the specified vector. +* +* This routine is much slower than magnitudeBetweenSquared(). +* +* @param vector The other endpoint of the delta vector +* @return The magnitude of the delta vector +* @see Vector::magnitudeBetweenSquared() +*/ + +inline real Vector::magnitudeXZBetween(const Vector &vec) const +{ + return sqrt(magnitudeXZBetweenSquared(vec)); +} + +// ---------------------------------------------------------------------- +/** +* Calculate the square of the magnitude of the vector between this vector and the specified vector. +* +* This routine is much faster than magnitudeBetween(). +* +* @param vector The other endpoint of the delta vector +* @return The square of the magnitude of the delta vector +* @see Vector::magnitudeBetween() +*/ + +inline real Vector::magnitudeYZBetweenSquared(const Vector &vec) const +{ + return (sqr(y - vec.y) + sqr(z - vec.z)); +} + +// ---------------------------------------------------------------------- +/** +* Calculate the magnitude of the vector between this vector and the specified vector. +* +* This routine is much slower than magnitudeBetweenSquared(). +* +* @param vector The other endpoint of the delta vector +* @return The magnitude of the delta vector +* @see Vector::magnitudeBetweenSquared() +*/ + +inline real Vector::magnitudeYZBetween(const Vector &vec) const +{ + return sqrt(magnitudeYZBetweenSquared(vec)); +} + +// ---------------------------------------------------------------------- +/** + * Reverse the direction of the vector. + * + * This routine simple negates each component of the vector + */ + +inline const Vector Vector::operator -(void) const +{ + return Vector(-x, -y, -z); +} + +// ---------------------------------------------------------------------- +/** + * Subtract a vector from this vector and store the result back in this vector. + * + * This is the basic obvious -= operator overloaded for vectors + * + * @param rhs The vector to subtract from this vector + * @return A reference to this modified vector + */ + +inline Vector &Vector::operator -=(const Vector &rhs) +{ + x -= rhs.x; + y -= rhs.y; + z -= rhs.z; + return *this; +} + +// ---------------------------------------------------------------------- +/** + * Add a vector from this vector and store the result back in this vector. + * + * This is the basic obvious += operator overloaded for vectors. + * + * @param rhs The vector to add to this vector + * @return A reference to this modified vector + */ + +inline Vector &Vector::operator +=(const Vector &rhs) +{ + x += rhs.x; + y += rhs.y; + z += rhs.z; + return *this; +} + +// ---------------------------------------------------------------------- +/** + * Multiply this vector by a scalar. + * + * This is the basic obvious *= operator overloaded for vectors and scalars. + * + * @param scalar The vector to subtract from this vector + * @return A reference to this modified vector + */ + +inline Vector &Vector::operator *=(real scalar) +{ + x *= scalar; + y *= scalar; + z *= scalar; + return *this; +} + +// ---------------------------------------------------------------------- +/** + * Divide this vector by a scalar. + * + * This is the basic obvious /= operator overloaded for vectors and scalars. + * + * @param scalar The vector to subtract from this vector + * @return A reference to this modified vector + */ + +inline Vector &Vector::operator /=(real scalar) +{ + *this *= (CONST_REAL(1.0) / scalar); + return *this; +} + +// ---------------------------------------------------------------------- +/** + * Calculate the cross product between two vectors. + * + * This routine returns a temporary. + * + * Cross products are not communitive. + * + * @param rhs The right-hand size of the expression + * @return A vector that is the result of the cross product of the two vectors. + */ + +inline const Vector Vector::cross(const Vector &rhs) const +{ + return Vector(y * rhs.z - z * rhs.y, z * rhs.x - x * rhs.z, x * rhs.y - y * rhs.x); +} + +// ---------------------------------------------------------------------- +/** + * Add two vectors. + * + * This routine returns a temporary. + * + * @param rhs The right-hand size of the expression + * @return A vector that is the sum of the two arguments. + */ + +inline const Vector Vector::operator +(const Vector &rhs) const +{ + return Vector(x + rhs.x, y + rhs.y, z + rhs.z); +} + +// ---------------------------------------------------------------------- +/** + * Subtract two vectors. + * + * This routine returns a temporary. + * + * @param rhs The right-hand size of the expression + * @return A vector that is the result of the left-hand-side minus the right-hand-side + */ + +inline const Vector Vector::operator -(const Vector &rhs) const +{ + return Vector(x - rhs.x, y - rhs.y, z - rhs.z); +} + +// ---------------------------------------------------------------------- +/** + * Multiply a vector by a scalar. + * + * This routine returns a temporary. + * + * @param scalar The scalar to multiply by + * @return The source vector multiplied by the scalar + */ + +inline const Vector Vector::operator *(real scalar) const +{ + return Vector(x * scalar, y * scalar, z * scalar); +} + +// ---------------------------------------------------------------------- +/** + * Divide a vector by a scalar. + * + * This routine returns a temporary. + * + * @param scalar The scalar to multiply by + * @return The source vector divided by the scalar + */ + +inline const Vector Vector::operator /(real scalar) const +{ + const real multiplier(CONST_REAL(1.0) / scalar); + return Vector(x * multiplier, y * multiplier, z * multiplier); +} + +// ---------------------------------------------------------------------- +/** + * Multiply a vector by a scalar. + * + * This routine returns a temporary. + * + * @return The source vector multiplied by the scalar + */ + +inline const Vector operator *(real scalar, const Vector &vec) +{ + return Vector(vec.x * scalar, vec.y * scalar, vec.z * scalar); +} + +// ---------------------------------------------------------------------- +/** + * Test two vectors for equality. + * + * Floating-point math make may two very similiar expressions end up slightly + * different, thus showing inequality when the result is very, very close. + * + * @param rhs The right-hand size of the expression + * @return True if the vectors are exactly equal, otherwise false. + */ + +inline bool Vector::operator ==(const Vector &rhs) const +{ + return (x == rhs.x && y == rhs.y && z == rhs.z); //lint !e777 // Testing floats for equality +} + +// ---------------------------------------------------------------------- +/** + * Test two vectors for inequality. + * + * Floating-point math make may two very similiar expressions end up slightly + * different, thus showing inequality when the result is very, very close. + * + * @param rhs The right-hand size of the expression + * @return True if the vectors are not equal, otherwise false. + */ + +inline bool Vector::operator !=(const Vector &rhs) const +{ + return (x != rhs.x || y != rhs.y || z != rhs.z); //lint !e777 // Testing floats for equality +} + +// ---------------------------------------------------------------------- +/** + * Reflect an outgoing vector around this normal. + * + * This routine assumes that both this vector and the normal around which it + * is being reflected have the same origin (the dot product of the normal and + * the vertex is positive) + * + * @param incident Normal to reflect this vector around + * @return The reflected vector + */ + +inline const Vector Vector::reflectOutgoing(const Vector &incident) const +{ + const Vector &normal = *this; + return normal * (2 * normal.dot(incident)) - incident; +} + +// ---------------------------------------------------------------------- +/** + * Reflect an incoming vector around this normal. + * + * This routine assumes that the vector terminates at the normal + * (the dot product of the normal and the vertex is negative). + * + * @param incident Normal to reflect this vector around + * @return The reflected vector + */ + +inline const Vector Vector::reflectIncoming(const Vector &incident) const +{ + return reflectOutgoing(-incident); +} + +// ---------------------------------------------------------------------- +/** + * Compute the midpoint of two vectors. + * + * This routine just averages the three components separately. + * + * @param vector1 First endpoint + * @param vector2 Second endpoint + */ + +inline const Vector Vector::midpoint(const Vector &vector1, const Vector &vector2) +{ + return Vector((vector1.x + vector2.x) * CONST_REAL(0.5), (vector1.y + vector2.y) * CONST_REAL(0.5), (vector1.z + vector2.z) * CONST_REAL(0.5)); +} + +// ---------------------------------------------------------------------- +/** + * Linearly interpolate between two vectors. + * + * The time parameter should be between 0.0 and 1.0 inclusive in order to have + * the result be between the two endpoints. At time 0.0 the result will be + * vector1, and at time 1.0 the result will be vector2. + * + * @param vector1 Starting endpoint + * @param vector2 Terminating endpoint + * @param time + */ + +inline const Vector Vector::linearInterpolate(const Vector &vector1, const Vector &vector2, real time) +{ + return Vector(vector1.x + (vector2.x - vector1.x) * time, vector1.y + (vector2.y - vector1.y) * time, vector1.z + (vector2.z - vector1.z) * time); +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedMath/src/shared/Vector2d.h b/engine/shared/library/sharedMath/src/shared/Vector2d.h new file mode 100644 index 00000000..56c3b356 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/Vector2d.h @@ -0,0 +1,310 @@ +//=================================================================== +// +// Vector2d.h +// asommers 7-26-99 +// +// copyright 1999, bootprint entertainment +// +//=================================================================== + +#ifndef INCLUDED_Vector2d_H +#define INCLUDED_Vector2d_H + +//=================================================================== + +class Vector2d +{ +public: + + float x; + float y; + +public: + + Vector2d (); + Vector2d (float newX, float newY); + + void set (float newX, float newY); + void makeZero (); + bool isZero () const; + bool normalize (); + float dot (const Vector2d& vector) const; + float theta () const; + void rotate (float radians); + void rotate (float radians, const Vector2d& center); + + const Vector2d operator- () const; + const Vector2d operator+ (const Vector2d& rhs) const; + const Vector2d operator- (const Vector2d& rhs) const; + const Vector2d operator* (float scalar) const; + const Vector2d operator/ (float scalar) const; + + bool operator== (const Vector2d& rhs) const; + bool operator!= (const Vector2d& rhs) const; + + Vector2d& operator+= (const Vector2d& rhs); + Vector2d& operator-= (const Vector2d& rhs); + Vector2d& operator*= (float scalar); + Vector2d& operator/= (float scalar); + + float magnitude () const; + float magnitudeSquared () const; + float magnitudeBetween (const Vector2d& vector) const; + float magnitudeBetweenSquared (const Vector2d& vector) const; + + static const Vector2d linearInterpolate (const Vector2d& start, const Vector2d& end, float t); + static const Vector2d normalized (const Vector2d& vector, bool* result=0); + static const Vector2d normal (const Vector2d& vector, bool normalize, bool* result=0); +}; + +//=================================================================== + +inline Vector2d::Vector2d () : + x (0), + y (0) +{ +} + +//------------------------------------------------------------------- + +inline Vector2d::Vector2d (float newX, float newY) : + x (newX), + y (newY) +{ +} + +//------------------------------------------------------------------- + +inline void Vector2d::set (float newX, float newY) +{ + x = newX; + y = newY; +} + +//------------------------------------------------------------------- + +inline void Vector2d::makeZero () +{ + x = 0; + y = 0; +} + +//------------------------------------------------------------------- + +inline bool Vector2d::isZero () const +{ + return x == 0 && y == 0; +} + +//------------------------------------------------------------------- + +inline bool Vector2d::normalize () +{ + const float mag = magnitude (); + + if (mag < 0.00001f) + return false; + + *this /= mag; + + return true; +} + +//------------------------------------------------------------------- + +inline float Vector2d::dot (const Vector2d& vector) const +{ + return (x * vector.x) + (y * vector.y); +} + +//------------------------------------------------------------------- + +inline float Vector2d::theta () const +{ + return atan2(x, y); +} + +//------------------------------------------------------------------- + +inline void Vector2d::rotate (float radians) +{ + const float cosAngle = cos (radians); + const float sinAngle = sin (radians); + + const float oldX = x; + const float oldY = y; + + x = oldX * cosAngle - oldY * sinAngle; + y = oldX * sinAngle + oldY * cosAngle; +} + +//------------------------------------------------------------------- + +inline void Vector2d::rotate (float radians, const Vector2d& origin) +{ + const Vector2d point (x - origin.x, y - origin.y); + const float cosAngle = cos (radians); + const float sinAngle = sin (radians); + + x = origin.x + point.x * cosAngle - point.y * sinAngle; + y = origin.y + point.x * sinAngle + point.y * cosAngle; +} + +//------------------------------------------------------------------- + +inline const Vector2d Vector2d::operator- () const +{ + return Vector2d (-x, -y); +} + +//------------------------------------------------------------------- + +inline const Vector2d Vector2d::operator+ (const Vector2d& rhs) const +{ + return Vector2d (x + rhs.x, y + rhs.y); +} + +//------------------------------------------------------------------- + +inline const Vector2d Vector2d::operator- (const Vector2d& rhs) const +{ + return Vector2d (x - rhs.x, y - rhs.y); +} + +//------------------------------------------------------------------- + +inline const Vector2d Vector2d::operator* (float scalar) const +{ + return Vector2d (x * scalar, y * scalar); +} + +//------------------------------------------------------------------- + +inline const Vector2d Vector2d::operator/ (float scalar) const +{ + return operator* (RECIP (scalar)); +} + +//------------------------------------------------------------------- + +inline bool Vector2d::operator== (const Vector2d& rhs) const +{ + return x == rhs.x && y == rhs.y; +} + +//------------------------------------------------------------------- + +inline bool Vector2d::operator!= (const Vector2d& rhs) const +{ + return !operator== (rhs); +} + +//------------------------------------------------------------------- + +inline float Vector2d::magnitude () const +{ + return static_cast (sqrt (magnitudeSquared ())); +} + +//------------------------------------------------------------------- + +inline float Vector2d::magnitudeSquared () const +{ + return sqr (x) + sqr (y); +} + +//------------------------------------------------------------------- + +inline float Vector2d::magnitudeBetween (const Vector2d& vector) const +{ + return static_cast (sqrt (magnitudeBetweenSquared (vector))); +} + +//------------------------------------------------------------------- + +inline float Vector2d::magnitudeBetweenSquared (const Vector2d& vector) const +{ + return sqr (x - vector.x) + sqr (y - vector.y); +} + +//------------------------------------------------------------------- + +inline Vector2d& Vector2d::operator+= (const Vector2d& rhs) +{ + x += rhs.x; + y += rhs.y; + + return *this; +} + +//------------------------------------------------------------------- + +inline Vector2d& Vector2d::operator-= (const Vector2d& rhs) +{ + x -= rhs.x; + y -= rhs.y; + + return *this; +} + +//------------------------------------------------------------------- + +inline Vector2d& Vector2d::operator*= (float scalar) +{ + x *= scalar; + y *= scalar; + + return *this; +} + +//------------------------------------------------------------------- + +inline Vector2d& Vector2d::operator/= (float scalar) +{ + *this *= RECIP (scalar); + + return *this; +} + +//------------------------------------------------------------------- + +inline const Vector2d Vector2d::linearInterpolate (const Vector2d& start, const Vector2d& end, float t) +{ + Vector2d v; + v.x = ::linearInterpolate (start.x, end.x, t); + v.y = ::linearInterpolate (start.y, end.y, t); + + return v; +} + +//------------------------------------------------------------------- + +inline const Vector2d Vector2d::normalized (const Vector2d& vector, bool* result) +{ + Vector2d v = vector; + bool r = v.normalize (); + if (result) + *result = r; + + return v; +} + +//------------------------------------------------------------------- + +inline const Vector2d Vector2d::normal (const Vector2d& vector, bool normalize, bool* result) +{ + Vector2d v (-vector.y, vector.x); + + if (normalize) + { + bool r = v.normalize (); + if (result) + *result = r; + } + + return v; +} + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedMath/src/shared/VectorArgb.cpp b/engine/shared/library/sharedMath/src/shared/VectorArgb.cpp new file mode 100644 index 00000000..78c26061 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/VectorArgb.cpp @@ -0,0 +1,39 @@ +// ====================================================================== +// +// VectorArgb.h +// jeff grills +// +// copyright 1999 Bootprint Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/VectorArgb.h" + +#include "sharedMath/PackedArgb.h" + +// ====================================================================== + +const VectorArgb VectorArgb::solidBlack (CONST_REAL(1), CONST_REAL(0), CONST_REAL(0), CONST_REAL(0)); +const VectorArgb VectorArgb::solidBlue (CONST_REAL(1), CONST_REAL(0), CONST_REAL(0), CONST_REAL(1)); +const VectorArgb VectorArgb::solidCyan (CONST_REAL(1), CONST_REAL(0), CONST_REAL(1), CONST_REAL(1)); +const VectorArgb VectorArgb::solidGreen (CONST_REAL(1), CONST_REAL(0), CONST_REAL(1), CONST_REAL(0)); +const VectorArgb VectorArgb::solidRed (CONST_REAL(1), CONST_REAL(1), CONST_REAL(0), CONST_REAL(0)); +const VectorArgb VectorArgb::solidMagenta(CONST_REAL(1), CONST_REAL(1), CONST_REAL(0), CONST_REAL(1)); +const VectorArgb VectorArgb::solidYellow (CONST_REAL(1), CONST_REAL(1), CONST_REAL(1), CONST_REAL(0)); +const VectorArgb VectorArgb::solidWhite (CONST_REAL(1), CONST_REAL(1), CONST_REAL(1), CONST_REAL(1)); +const VectorArgb VectorArgb::solidGray (CONST_REAL(1), CONST_REAL(0.5), CONST_REAL(0.5), CONST_REAL(0.5)); + +const real oo255 = 1.0f / 255.0f; + +// ====================================================================== + +VectorArgb::VectorArgb(const PackedArgb &argb) +: a(static_cast(argb.getA()) * oo255), + r(static_cast(argb.getR()) * oo255), + g(static_cast(argb.getG()) * oo255), + b(static_cast(argb.getB()) * oo255) +{ +} + +// ====================================================================== diff --git a/engine/shared/library/sharedMath/src/shared/VectorArgb.h b/engine/shared/library/sharedMath/src/shared/VectorArgb.h new file mode 100644 index 00000000..6afbc2b0 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/VectorArgb.h @@ -0,0 +1,155 @@ +// ====================================================================== +// +// VectorArgb.h +// Portions Copyright 1998 Bootprint Entertainment +// Portions Copyright 2003 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_VectorArgb_H +#define INCLUDED_VectorArgb_H + +// ====================================================================== + +class PackedArgb; + +// ====================================================================== + +class VectorArgb +{ +public: + + static const VectorArgb solidBlack; + static const VectorArgb solidBlue; + static const VectorArgb solidCyan; + static const VectorArgb solidGray; + static const VectorArgb solidGreen; + static const VectorArgb solidRed; + static const VectorArgb solidMagenta; + static const VectorArgb solidYellow; + static const VectorArgb solidWhite; + + real a; + real r; + real g; + real b; + + VectorArgb(void); + VectorArgb(real newA, real newR, real newG, real newB); + VectorArgb(const PackedArgb &argb); + + void set(real newA, real newR, real newG, real newB); + float rgbIntensity() const; + + bool operator ==(const VectorArgb &rhs) const; + bool operator !=(const VectorArgb &rhs) const; + const VectorArgb operator *(float scalar) const; + VectorArgb operator+(const VectorArgb &o) const { return VectorArgb(a+o.a, r+o.r, g+o.g, b+o.b); } + + static const VectorArgb linearInterpolate(const VectorArgb &color1, const VectorArgb &color2, real time); + + uint32 convertToUint32() const; + uint32 convertToUint32NoClamp() const; +}; + +// ====================================================================== + +inline VectorArgb::VectorArgb(void) +: a(CONST_REAL(1)), + r(CONST_REAL(0)), + g(CONST_REAL(0)), + b(CONST_REAL(0)) +{ +} + +// ---------------------------------------------------------------------- + +inline VectorArgb::VectorArgb(real newA, real newR, real newG, real newB) +: a(newA), + r(newR), + g(newG), + b(newB) +{ +} + +// ---------------------------------------------------------------------- + +inline void VectorArgb::set(real newA, real newR, real newG, real newB) +{ + a = newA; + r = newR; + g = newG; + b = newB; +} + +// ---------------------------------------------------------------------- + +inline bool VectorArgb::operator ==(const VectorArgb &rhs) const +{ + return ((a == rhs.a) && (r == rhs.r) && (g == rhs.g) && (b == rhs.b)); //lint !e777 // testing floats for equality +} + +// ---------------------------------------------------------------------- + +inline bool VectorArgb::operator !=(const VectorArgb &rhs) const +{ + return !(*this == rhs); +} + +// ---------------------------------------------------------------------- + +inline float VectorArgb::rgbIntensity() const +{ + return abs(r) * 0.30f + abs(g) * 0.59f + abs(b) * 0.11f; +} + +// ---------------------------------------------------------------------- +/** + * Linearly interpolate between two VectorArgbs. + * + * The time parameter should be between 0.0 and 1.0 inclusive in order to have + * the result be between the two endpoints. At time 0.0 the result will be + * color1, and at time 1.0 the result will be color2. + * + * @param color1 Starting endpoint + * @param color2 Terminating endpoint + * @param time + */ + +inline const VectorArgb VectorArgb::linearInterpolate(const VectorArgb &color1, const VectorArgb &color2, real time) +{ + return VectorArgb(color1.a + (color2.a - color1.a) * time, color1.r + (color2.r - color1.r) * time, color1.g + (color2.g - color1.g) * time, color1.b + (color2.b - color1.b) * time); +} + +// ---------------------------------------------------------------------- + +inline uint32 VectorArgb::convertToUint32() const +{ + const uint32 a32 = clamp(static_cast(0), static_cast(a * 255.0f), static_cast(255)); + const uint32 r32 = clamp(static_cast(0), static_cast(r * 255.0f), static_cast(255)); + const uint32 g32 = clamp(static_cast(0), static_cast(g * 255.0f), static_cast(255)); + const uint32 b32 = clamp(static_cast(0), static_cast(b * 255.0f), static_cast(255)); + return (a32 << 24) | (r32 << 16) | (g32 << 8) | (b32 << 0); +} + +// ---------------------------------------------------------------------- + +inline uint32 VectorArgb::convertToUint32NoClamp() const +{ + const uint32 a32 = static_cast(a * 255.0f); + const uint32 r32 = static_cast(r * 255.0f); + const uint32 g32 = static_cast(g * 255.0f); + const uint32 b32 = static_cast(b * 255.0f); + return (a32 << 24) | (r32 << 16) | (g32 << 8) | (b32 << 0); +} + +// ---------------------------------------------------------------------- + +inline const VectorArgb VectorArgb::operator *(const float scalar) const +{ + return VectorArgb(a * scalar, r * scalar, g * scalar, b * scalar); +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedMath/src/shared/VectorRgba.cpp b/engine/shared/library/sharedMath/src/shared/VectorRgba.cpp new file mode 100644 index 00000000..6ab2970f --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/VectorRgba.cpp @@ -0,0 +1,44 @@ +// ====================================================================== +// +// VectorRgba.h +// +// Portions Copyright 1999 Bootprint Entertainment +// Portions Copyright 2004 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/VectorRgba.h" + +#include "sharedMath/PackedArgb.h" + +// ====================================================================== + +const VectorRgba VectorRgba::solidBlack (0.0f, 0.0f, 0.0f, 1.0f); +const VectorRgba VectorRgba::solidBlue (0.0f, 0.0f, 1.0f, 1.0f); +const VectorRgba VectorRgba::solidCyan (0.0f, 1.0f, 1.0f, 1.0f); +const VectorRgba VectorRgba::solidGreen (0.0f, 1.0f, 0.0f, 1.0f); +const VectorRgba VectorRgba::solidRed (1.0f, 0.0f, 0.0f, 1.0f); +const VectorRgba VectorRgba::solidMagenta(1.0f, 0.0f, 1.0f, 1.0f); +const VectorRgba VectorRgba::solidYellow (1.0f, 1.0f, 0.0f, 1.0f); +const VectorRgba VectorRgba::solidWhite (1.0f, 1.0f, 1.0f, 1.0f); +const VectorRgba VectorRgba::solidGray (0.5f, 0.5f, 0.5f, 1.0f); + +namespace VectorRgbaNamespace +{ + const real oo255 = 1.0f / 255.0f; +} +using namespace VectorRgbaNamespace; + +// ====================================================================== + +VectorRgba::VectorRgba(PackedArgb const & argb) +: + r(static_cast(argb.getR()) * oo255), + g(static_cast(argb.getG()) * oo255), + b(static_cast(argb.getB()) * oo255), + a(static_cast(argb.getA()) * oo255) +{ +} + +// ====================================================================== diff --git a/engine/shared/library/sharedMath/src/shared/VectorRgba.h b/engine/shared/library/sharedMath/src/shared/VectorRgba.h new file mode 100644 index 00000000..6e522e24 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/VectorRgba.h @@ -0,0 +1,148 @@ +// ====================================================================== +// +// VectorRgba.h +// Portions Copyright 1998 Bootprint Entertainment +// Portions Copyright 2003-2004 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_VectorRgba_H +#define INCLUDED_VectorRgba_H + +// ====================================================================== + +class PackedArgb; + +// ====================================================================== + +class VectorRgba +{ +public: + + static const VectorRgba solidBlack; + static const VectorRgba solidBlue; + static const VectorRgba solidCyan; + static const VectorRgba solidGray; + static const VectorRgba solidGreen; + static const VectorRgba solidRed; + static const VectorRgba solidMagenta; + static const VectorRgba solidYellow; + static const VectorRgba solidWhite; + +public: + + float r; + float g; + float b; + float a; + +public: + + VectorRgba(); + VectorRgba(float newR, float newG, float newB, float newA); + VectorRgba(PackedArgb const & argb); + + void set(float newR, float newG, float newB, float newA); + float rgbIntensity() const; + + bool operator ==(VectorRgba const & rhs) const; + bool operator !=(VectorRgba const & rhs) const; + VectorRgba const operator *(float scalar) const; + + static VectorRgba const linearInterpolate(VectorRgba const & color1, VectorRgba const & color2, float time); + + uint32 convertToUint32() const; +}; + +// ====================================================================== + +inline VectorRgba::VectorRgba() +: + r(0.0f), + g(0.0f), + b(0.0f), + a(1.0f) + { +} + +// ---------------------------------------------------------------------- + +inline VectorRgba::VectorRgba(float const newR, float const newG, float const newB, float const newA) +: + r(newR), + g(newG), + b(newB), + a(newA) + { +} + +// ---------------------------------------------------------------------- + +inline void VectorRgba::set(float const newR, float const newG, float const newB, float const newA) +{ + r = newR; + g = newG; + b = newB; + a = newA; +} + +// ---------------------------------------------------------------------- + +inline bool VectorRgba::operator ==(VectorRgba const & rhs) const +{ + return ((r == rhs.r) && (g == rhs.g) && (b == rhs.b) && (a == rhs.a)); //lint !e777 // testing floats for equality +} + +// ---------------------------------------------------------------------- + +inline bool VectorRgba::operator !=(VectorRgba const & rhs) const +{ + return !(*this == rhs); +} + +// ---------------------------------------------------------------------- + +inline float VectorRgba::rgbIntensity() const +{ + return abs(r) * 0.30f + abs(g) * 0.59f + abs(b) * 0.11f; +} + +// ---------------------------------------------------------------------- +/** + * Linearly interpolate between two VectorRgbas. + * + * The time parameter should be between 0.0 and 1.0 inclusive in order to have + * the result be between the two endpoints. At time 0.0 the result will be + * color1, and at time 1.0 the result will be color2. + * + * @param color1 Starting endpoint + * @param color2 Terminating endpoint + * @param time + */ + +inline VectorRgba const VectorRgba::linearInterpolate(VectorRgba const & color1, VectorRgba const & color2, float time) +{ + return VectorRgba(color1.r + (color2.r - color1.r) * time, color1.g + (color2.g - color1.g) * time, color1.b + (color2.b - color1.b) * time, color1.a + (color2.a - color1.a) * time); +} + +// ---------------------------------------------------------------------- + +inline uint32 VectorRgba::convertToUint32() const +{ + const uint32 a32 = clamp(static_cast(0), static_cast(a * 255.0f), static_cast(255)); + const uint32 r32 = clamp(static_cast(0), static_cast(r * 255.0f), static_cast(255)); + const uint32 g32 = clamp(static_cast(0), static_cast(g * 255.0f), static_cast(255)); + const uint32 b32 = clamp(static_cast(0), static_cast(b * 255.0f), static_cast(255)); + return (a32 << 24) | (r32 << 16) | (g32 << 8) | (b32 << 0); +} + +// ---------------------------------------------------------------------- + +inline VectorRgba const VectorRgba::operator *(float const scalar) const +{ + return VectorRgba(r * scalar, g * scalar, b * scalar, a * scalar); +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedMath/src/shared/Volume.cpp b/engine/shared/library/sharedMath/src/shared/Volume.cpp new file mode 100644 index 00000000..65a8c69f --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/Volume.cpp @@ -0,0 +1,289 @@ +// ====================================================================== +// +// Volume.cpp +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/Volume.h" + +#include "sharedMath/Plane.h" +#include "sharedMath/Sphere.h" +#include "sharedMath/Vector.h" + +// ====================================================================== +// Create an open-ended volume +// +// This constructor creates an open ended volume by projecting a ray from originPoint +// through all the vertices in vertexList, and capping the volume off with the plane +// formed by vertexList. This routine assumes the vertices in vertexList form a +// planar convex polygon and wind in a clockwise order. +// +// @param originPoint Point from which the volume is cast. +// @param numberOfVertices Number of vertices in vertexList. +// @param vertexList Co-planar set of points describing the siloutte edges of the volume. + +Volume::Volume(const Vector &originPoint, const int numberOfVertices, const Vector * const vertexList) +: + m_numberOfPlanes(numberOfVertices + 1), + m_plane(new Plane[ static_cast(m_numberOfPlanes) ]) +{ + NOT_NULL(vertexList); + DEBUG_FATAL(numberOfVertices < 3, ("At least 3 vertices are necessary")); + + // build the cap + m_plane[0].set(vertexList[0], vertexList[1], vertexList[2]); + + // build the sides + for (int i = 1; i < numberOfVertices; ++i) + m_plane[i].set(originPoint, vertexList[i-1], vertexList[i]); + m_plane[numberOfVertices].set(originPoint, vertexList[numberOfVertices-1], vertexList[0]); +} + +// ---------------------------------------------------------------------- +/** + * Create an undefined volume + * + * This constructor creates a volume consisting of the specified number of planes, + * but does not set up the plane data. + * + * @param numberOfPlanes Number of planes in the volume. + */ + +Volume::Volume(const int numberOfPlanes) +: + m_numberOfPlanes(numberOfPlanes), + m_plane(new Plane[ static_cast(m_numberOfPlanes) ]) +{ +} + +// ---------------------------------------------------------------------- +/** + * Construct a new volume from another, transformed by the specified transformation. + * + * @param other The other volume + * @param trans The transform to be applied. + */ + +Volume::Volume (const Volume &rhs, const Transform &newTransform) +: + m_numberOfPlanes(rhs.m_numberOfPlanes), + m_plane(new Plane[ static_cast(m_numberOfPlanes) ]) +{ + for (int i = 0; i < m_numberOfPlanes; ++i) + m_plane [i].set(rhs.m_plane[i], newTransform); +} + +// ---------------------------------------------------------------------- + +Volume::~Volume() +{ + delete [] m_plane; +} + +// ---------------------------------------------------------------------- +/** + * Set a specific plane in the volume + * + * This routine can be used to build up a volume after having used the + * constructor that takes a number of planes. + * + * @param index The plane to modify. + * @param plane The new value for the plane data. + */ + +void Volume::setPlane(const int index, const Plane &plane) +{ + DEBUG_FATAL(index < 0 || index >= m_numberOfPlanes, ("index out of range %d/%d", index, m_numberOfPlanes)); + m_plane[index] = plane; +} + +// ---------------------------------------------------------------------- +/** + * Set a specific plane in the volume + * + * This routine can be used to build up a volume after having used the + * constructor that takes a number of planes. + * + * @param index The plane to modify. + * @param plane The new value for the plane data. + */ + +const Plane &Volume::getPlane(const int index) const +{ + DEBUG_FATAL(index < 0 || index >= m_numberOfPlanes, ("index out of range %d/%d", index, m_numberOfPlanes)); + return m_plane[index]; +} + +// ---------------------------------------------------------------------- +/** + * Test a point against a volume + * + * @param point Point to test. + * @return True if the point is within the volume. + */ + +bool Volume::contains(const Vector &point) const +{ + for (int i = 0; i < m_numberOfPlanes; ++i) + if (m_plane[i].computeDistanceTo(point) > 0) + return false; + + return true; +} + +// ---------------------------------------------------------------------- +/** + * See if the volume completely contains the sphere + * + * @param sphere The sphere to check. + * @return True if the entire sphere is within the volume, otherwise false. + */ + +bool Volume::contains(const Sphere &sphere) const +{ + const Vector ¢er = sphere.getCenter(); + const real radius = sphere.getRadius(); + + for (int i = 0; i < m_numberOfPlanes; ++i) + if (m_plane[i].computeDistanceTo(center) > -radius) + return false; + + return true; +} + +// ---------------------------------------------------------------------- +/** + * Test a point cloud against a volume + * + * @param pointCloud Point cloud to test. + * @param numberOfPoints Number of points in the point cloud. + * @return True if the point is within the volume. + */ + +bool Volume::contains(const Vector *pointCloud, int numberOfPoints) const +{ + NOT_NULL(pointCloud); + DEBUG_FATAL(numberOfPoints <= 0, ("numberOfPoints is less than 1")); + + for (int i = 0; i < m_numberOfPlanes; ++i) + for (int j = 0; i < numberOfPoints; ++j) + if (m_plane[i].computeDistanceTo(pointCloud[j]) > 0) + return false; + + return true; +} + +// ---------------------------------------------------------------------- +/** + * See if the volume intersects a sphere. + * + * The sphere is in the volume if any portion of it is within the volume. + * + * @param sphere The sphere to check. + * @return True if the any portion of the sphere is within the volume, otherwise false. + */ + +bool Volume::intersects(const Sphere &sphere) const +{ + const Vector ¢er = sphere.getCenter(); + const real radius = sphere.getRadius(); + + for (int i = 0; i < m_numberOfPlanes; ++i) + if (m_plane[i].computeDistanceTo(center) > radius) + return false; + + return true; +} + +// ---------------------------------------------------------------------- +/** + * See if the volume intersects the segment. + * + * The segment is considered to be in the volume if both points test on the negative side of any plane + * + * @param start Start point of segment. + * @param end End point of segment. + * @return False if any segment is on the negative side of any plane + */ + +bool Volume::intersects(Vector const & start, Vector const & end) const +{ + for (int i = 0; i < m_numberOfPlanes; ++i) + { + Plane const & plane = m_plane[i]; + if (plane.computeDistanceTo(start) < 0.f && plane.computeDistanceTo(end) < 0.f) + return false; + } + + return true; +} + +// ---------------------------------------------------------------------- +/** + * Fast Conservative check of a point cloud against the volume + * + * This routine will return true if the point could is completely outside any one + * plane of the volume. If the routine returns true, the point cloud is definitely + * outside the volume. However, a false result does not guarentee that the point + * cloud intersects the volume. + * + * @param pointCloud Point cloud to test. + * @param numberOfPoints Number of points in the point cloud. + * @return See remarks for more information. + */ + +bool Volume::fastConservativeExcludes(const Vector *pointCloud, int numberOfPoints) const +{ + NOT_NULL(pointCloud); + DEBUG_FATAL(numberOfPoints <= 0, ("numberOfPoints is less than 1")); + + // check plane by plane + for (int i = 0; i < m_numberOfPlanes; ++i) + { + bool outside = true; + for (int j = 0; outside && j < numberOfPoints; ++j) + outside = m_plane[i].computeDistanceTo(pointCloud[j]) > 0; + + if (outside) + return true; + } + + return false; +} +// ---------------------------------------------------------------------- +/** + * Transform the volume by the specified transformation. + * + * @param transform The transform to be applied. + */ + +void Volume::transform(const Transform &newTransform) +{ + for (int i = 0; i < m_numberOfPlanes; ++i) + m_plane[i].transform(newTransform); +} + +// ---------------------------------------------------------------------- +/** + * Transform the specified volume by the specified transformation. + * + * @param source The source volume to transform. + * @param transform The transform to be applied. + */ + +void Volume::transform(const Volume &source, const Transform &newTransform) +{ + if (m_numberOfPlanes != source.m_numberOfPlanes) + { + delete [] m_plane; + m_numberOfPlanes = source.m_numberOfPlanes; + m_plane = new Plane[ static_cast(m_numberOfPlanes) ]; + } + + for (int i = 0; i < m_numberOfPlanes; ++i) + m_plane[i].set(source.m_plane[i], newTransform); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedMath/src/shared/Volume.h b/engine/shared/library/sharedMath/src/shared/Volume.h new file mode 100644 index 00000000..61eaff49 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/Volume.h @@ -0,0 +1,68 @@ +// ====================================================================== +// +// Volume.h +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef VOLUME_H +#define VOLUME_H + +// ====================================================================== + +class Plane; +class Sphere; +class Transform; +class Vector; + +// ====================================================================== + +class Volume +{ +public: + + explicit Volume(int numberOfPlanes); + Volume(const Vector &originPoint, int numberOfVertices, const Vector *vertexList); + Volume (const Volume &rhs, const Transform &transform); + ~Volume(); + + int getNumberOfPlanes() const; + void setPlane(int index, const Plane &plane); + const Plane &getPlane(int index) const; + + bool contains(const Vector &point) const; + bool contains(const Sphere &sphere) const; + bool contains(const Vector *pointCloud, int numberOfPoints) const; + + bool intersects(const Sphere &sphere) const; + bool intersects(Vector const & start, Vector const & end) const; + bool fastConservativeExcludes(const Vector *pointCloud, int numberOfPoints) const; + + void transform(const Transform &transform); + void transform(const Volume &source, const Transform &transform); + +private: + + // disabled + Volume(const Volume &); + Volume &operator =(const Volume &); + +private: + + int m_numberOfPlanes; + Plane *m_plane; +}; + +// ====================================================================== +// Get the number of planes in the volume +// +// @return The number of planes in the volume. + +inline int Volume::getNumberOfPlanes() const +{ + return m_numberOfPlanes; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedMath/src/shared/WaveForm.cpp b/engine/shared/library/sharedMath/src/shared/WaveForm.cpp new file mode 100644 index 00000000..92af3afe --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/WaveForm.cpp @@ -0,0 +1,1130 @@ +// ============================================================================ +// +// WaveForm.cpp +// Copyright Sony Online Entertainment +// +// ============================================================================ + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/WaveForm.h" + +#include "sharedFile/Iff.h" +#include "sharedMath/CatmullRomSpline.h" +#include "sharedRandom/Random.h" + +// ============================================================================ +// +// WaveFormNamespace +// +// ============================================================================ + +namespace WaveFormNamespace +{ +#ifdef _DEBUG + int s_singleValueMiss = 0; + int s_singleValueHit = 0; + int s_splineCalculationCount = 0; + int s_linearCalculationCount = 0; +#endif // _DEBUG +}; + +using namespace WaveFormNamespace; + +// ============================================================================ +// +// WaveFormControlPointIter +// +// ============================================================================ + +//----------------------------------------------------------------------------- +WaveFormControlPointIter::WaveFormControlPointIter() + : m_iter() + , m_initialPercent(0.0f) +{ +} + +//----------------------------------------------------------------------------- +void WaveFormControlPointIter::reset(WaveForm::ControlPointList::const_iterator const &iter) +{ + m_iter = iter; + m_initialPercent = Random::randomReal(0.0f, 1.0f); +} + +// ============================================================================ +// +// WaveFormControlPoint +// +// ============================================================================ + +float const WaveFormControlPoint::m_theValueMax = 10000; +float const WaveFormControlPoint::m_theValueMin = -10000; + +//----------------------------------------------------------------------------- +WaveFormControlPoint::WaveFormControlPoint() + : m_percent(0.0f) + , m_value(0.0f) + , m_randomMax(0.0f) + , m_randomMin(0.0f) +{ +} + +//----------------------------------------------------------------------------- +WaveFormControlPoint::WaveFormControlPoint(float const percent, float const value, float const randomMax, float const randomMin) + : m_percent(percent) + , m_value(value) + , m_randomMax(randomMax) + , m_randomMin(randomMin) +{ + DEBUG_FATAL(percent < 0.0f, ("WaveFormControlPoint::WaveFormControlPoint() - percent (%.3f) must be >= 0", percent)); + DEBUG_FATAL(percent > 1.0f, ("WaveFormControlPoint::WaveFormControlPoint() - percent (%.3f) must be <= 1", percent)); + DEBUG_FATAL(randomMin < 0.0f, ("WaveFormControlPoint::WaveFormControlPoint() - randomMax (%.3f) must be >= 0", randomMin)); + DEBUG_FATAL(randomMax < 0.0f, ("WaveFormControlPoint::WaveFormControlPoint() - randomMax (%.3f) must be >= 0", randomMax)); + + // Clamp the value to the absolute min and max value to prevent weirdness + + m_value = clamp(m_theValueMin, m_value, m_theValueMax); +} + +//----------------------------------------------------------------------------- +float WaveFormControlPoint::getPercent() const +{ + return m_percent; +} + +//----------------------------------------------------------------------------- +float WaveFormControlPoint::getValue() const +{ + return m_value; +} + +//----------------------------------------------------------------------------- +float WaveFormControlPoint::getRandomMin() const +{ + return m_randomMin; +} + +//----------------------------------------------------------------------------- +float WaveFormControlPoint::getRandomMax() const +{ + return m_randomMax; +} + +//----------------------------------------------------------------------------- +void WaveFormControlPoint::setValue(float const value) +{ + m_value = value; +} + +//----------------------------------------------------------------------------- +void WaveFormControlPoint::setRandomMin(float const randomMin) +{ + m_randomMin = randomMin; +} + +//----------------------------------------------------------------------------- +void WaveFormControlPoint::setRandomMax(float const randomMax) +{ + m_randomMax = randomMax; +} + +// ============================================================================ +// +// WaveForm +// +// ============================================================================ + +#define TAG_WVFM TAG(W,V,F,M) + +//----------------------------------------------------------------------------- +WaveForm::WaveForm() + : m_controlPointList() + , m_interpolationType(IT_linear) + , m_sampleType(ST_continuous) + , m_valueMax(10000.0f) + , m_valueMin(-10000.0f) + , m_singleValue(false) +#ifdef _DEBUG + , m_name("") + , m_controlPointCount(0) +#endif // _DEBUG +{ +} + +//----------------------------------------------------------------------------- +WaveForm::WaveForm(WaveForm const &rhs) + : m_controlPointList(rhs.m_controlPointList) + , m_interpolationType(rhs.m_interpolationType) + , m_sampleType(rhs.m_sampleType) + , m_valueMax(rhs.m_valueMax) + , m_valueMin(rhs.m_valueMin) + , m_singleValue(rhs.m_singleValue) +#ifdef _DEBUG + , m_name(rhs.m_name) + , m_controlPointCount(static_cast(m_controlPointList.size())) +#endif // _DEBUG +{ +} + +//----------------------------------------------------------------------------- +WaveForm::~WaveForm() +{ +} + +//----------------------------------------------------------------------------- +WaveForm &WaveForm::operator =(WaveForm const &rhs) +{ + if (this == &rhs) + { + return *this; + } + + m_controlPointList = rhs.m_controlPointList; + +#ifdef _DEBUG + m_controlPointCount = static_cast(m_controlPointList.size()); + m_name = rhs.m_name; +#endif // _DEBUG + + m_interpolationType = rhs.m_interpolationType; + m_sampleType = rhs.m_sampleType; + m_valueMax = rhs.m_valueMax; + m_valueMin = rhs.m_valueMin; + m_singleValue = rhs.m_singleValue; + + return *this; +} + +#ifdef _DEBUG +//----------------------------------------------------------------------------- +int WaveForm::getSingleValueHit() +{ + return s_singleValueHit; +} + +//----------------------------------------------------------------------------- +int WaveForm::getSingleValueMiss() +{ + return s_singleValueMiss; +} + +//----------------------------------------------------------------------------- +int WaveForm::getSplineCalculationCount() +{ + return s_splineCalculationCount; +} + +//----------------------------------------------------------------------------- +int WaveForm::getLinearCalculationCount() +{ + return s_linearCalculationCount; +} + +#endif // _DEBUG + +//----------------------------------------------------------------------------- +void WaveForm::setValueMax(float const max) +{ + // Check for ridiculous values + + DEBUG_FATAL(max >= 64000.0f, ("WaveForm::setValueMax() - Ridiculous max value set (%.3f)", max)); + + m_valueMax = max; +} + +//----------------------------------------------------------------------------- +void WaveForm::setValueMin(float const min) +{ + // Check for ridiculous values + + DEBUG_FATAL(min <= -64000.0f, ("WaveForm::setValueMax() - Ridiculous minvalue set (%.3f)", min)); + + m_valueMin = min; +} + +//----------------------------------------------------------------------------- +float const WaveForm::getValueMax() const +{ + return m_valueMax; +} + +//----------------------------------------------------------------------------- +float const WaveForm::getValueMin() const +{ + return m_valueMin; +} + +//----------------------------------------------------------------------------- +void WaveForm::calculateMinMax(float &max, float &min) +{ + // Recalculate the min and max values + + max = m_controlPointList.begin()->getValue(); + min = m_controlPointList.begin()->getValue(); + + for (ControlPointList::const_iterator current = m_controlPointList.begin(); current != m_controlPointList.end(); ++current) + { + float const valuePlusRandom = current->getValue() + current->getRandomMax(); + float const valueMinusRandom = current->getValue() - current->getRandomMin(); + + if (valuePlusRandom > m_valueMax) + { + max = m_valueMax; + } + else if (max < valuePlusRandom) + { + max = valuePlusRandom; + } + + if (valueMinusRandom < m_valueMin) + { + min = m_valueMin; + } + else if (min > valueMinusRandom) + { + min = valueMinusRandom; + } + } + + DEBUG_FATAL(m_valueMin > m_valueMax, ("WaveForm::calculateMinMax() - m_valueMin (%.3f) > m_valueMax (%.3f)", m_valueMin, m_valueMax)); + + // Make sure to prevent wackiness by clamping the minimum space represented + // between the min and max values + + float const epsilon = 0.1f; + float foo = 0.0f; + + if ((max - min) <= epsilon) + { + foo = (epsilon - (max - min)) / 2.0f; + } + + // Center the values in the waveform + + min -= foo; + max += foo; + + DEBUG_FATAL(m_valueMin > (m_valueMax - epsilon), ("WaveForm::calculateMinMax() - m_valueMin (%.3f) <= (m_valueMax (%.3f) - epsilon (%.3f))", m_valueMin, m_valueMax, epsilon)); + + // Make sure the min and max are still within bounds + + if (min < m_valueMin) + { + min += foo; + max += foo; + } + else if (max > m_valueMax) + { + min -= foo; + max -= foo; + } + + // Make sure the values are legit + + DEBUG_FATAL(min > max, ("WaveForm::calculateMinMax() - min (%.3f) > max (%.3f)", min, max)); + DEBUG_FATAL(min < m_valueMin, ("WaveForm::calculateMinMax() - min (%.3f) < m_valueMin (%.3f)", m_valueMin, max)); + DEBUG_FATAL(max > m_valueMax, ("WaveForm::calculateMinMax() - max (%.3f) > m_valueMax (%.3f)", max, m_valueMax)); +} + +//----------------------------------------------------------------------------- +void WaveForm::copyControlPoints(WaveForm const &waveForm) +{ + m_interpolationType = waveForm.m_interpolationType; + m_sampleType = waveForm.m_sampleType; + + // Remove all the current control points + + clear(); + + // Insert the control points from the specified waveform + + ControlPointList::const_iterator current = waveForm.m_controlPointList.begin(); + + for (; current != waveForm.m_controlPointList.end(); ++current) + { + insert(*current); + } +} + +//----------------------------------------------------------------------------- +void WaveForm::insert(WaveFormControlPoint const &controlPoint) +{ + WaveFormControlPoint newControlPoint(controlPoint); + + // Make sure the value is in a valid range + + clampValue(newControlPoint); + + // Insert the control point in the correct place in the list based on the + // percent value + + bool inserted = false; + ControlPointList::iterator current = m_controlPointList.begin(); + + for (; current != m_controlPointList.end(); ++current) + { + if (newControlPoint.getPercent() < current->getPercent()) + { + IGNORE_RETURN(m_controlPointList.insert(current, newControlPoint)); + inserted = true; + break; + } + } + + // This handles inserting in to the list if there is nothing in the list + // or if the item needs to be at the end of the list + + if (!inserted) + { + IGNORE_RETURN(m_controlPointList.insert(m_controlPointList.end(), newControlPoint)); + } + +#ifdef _DEBUG + m_controlPointCount = static_cast(m_controlPointList.size()); +#endif // _DEBUG +} + +//----------------------------------------------------------------------------- +void WaveForm::remove(ControlPointList::iterator &iter) +{ + DEBUG_FATAL(!verifyIteratorValid(iter), ("WaveForm::remove() - Invalid iterator")); + + iter = m_controlPointList.erase(iter); + +#ifdef _DEBUG + m_controlPointCount = static_cast(m_controlPointList.size()); +#endif // _DEBUG +} + +//----------------------------------------------------------------------------- +void WaveForm::setControlPoint(ControlPointList::const_iterator const &iter, WaveFormControlPoint const &controlPoint) +{ + DEBUG_FATAL(!verifyIteratorValid(iter), ("WaveForm::setControlPoint() - Invalid iterator")); + + for (ControlPointList::iterator current = m_controlPointList.begin(); current != m_controlPointList.end(); ++current) + { + if (current == iter) + { + // Set control point + + *current = controlPoint; + + // Clamp the value to the max and min value + + clampValue(*current); + + // Clamp the percent to the neighboring control points + + clampPercent(current); + + break; + } + } +} + +//----------------------------------------------------------------------------- +void WaveForm::clampValue(WaveFormControlPoint &controlPoint) const +{ + float const percent = controlPoint.getPercent(); + float value = controlPoint.getValue(); + float randomMax = controlPoint.getRandomMax(); + float randomMin = controlPoint.getRandomMin(); + + // Check the value + + if (value > m_valueMax) + { + value = m_valueMax; + } + else if (value < m_valueMin) + { + value = m_valueMin; + } + + // Check the random max + + if (value + randomMax > m_valueMax) + { + randomMax = m_valueMax - value; + } + + // Check the random min + + if (value - randomMin < m_valueMin) + { + randomMin = -(m_valueMin - value); + } + + controlPoint = WaveFormControlPoint(percent, value, randomMax, randomMin); +} + +//----------------------------------------------------------------------------- +void WaveForm::clampPercent(ControlPointList::iterator const &iter) +{ + DEBUG_FATAL(!verifyIteratorValid(iter), ("WaveForm::clampPercent() - Invalid iterator")); + + // Make sure the control point values are in the correct range + + float percent = iter->getPercent(); + + // Find the previous and next iterators so we can clamp this control point + // inside them + + ControlPointList::iterator current = m_controlPointList.begin(); + ControlPointList::iterator prev = current; + ControlPointList::iterator next = current; + int index = 1; + + for (; current != m_controlPointList.end(); ++current) + { + if (current == iter) + { + next = current; + ++next; + break; + } + + prev = current; + ++index; + } + + // Clamp the percent to previous percent + + if (iter == m_controlPointList.begin()) + { + percent = 0.0f; + } + else if (percent < prev->m_percent) + { + percent = prev->m_percent; + } + + // Clamp the percent to next percent + + if (index == static_cast(m_controlPointList.size())) + { + percent = 1.0f; + } + else if ((next != m_controlPointList.end()) && (percent > next->m_percent)) + { + percent = next->m_percent; + } + + // Set the new clamped values back into the iterator + + *iter = WaveFormControlPoint(percent, iter->getValue(), iter->getRandomMax(), iter->getRandomMin()); +} + +//----------------------------------------------------------------------------- +void WaveForm::clear() +{ + m_singleValue = false; + m_controlPointList.clear(); + +#ifdef _DEBUG + m_controlPointCount = 0; +#endif // _DEBUG +} + +//----------------------------------------------------------------------------- +WaveForm::InterpolationType WaveForm::getInterpolationType() const +{ + return m_interpolationType; +} + +//----------------------------------------------------------------------------- +WaveForm::SampleType WaveForm::getSampleType() const +{ + return m_sampleType; +} + +//----------------------------------------------------------------------------- +void WaveForm::setInterpolationType(InterpolationType const interpolationMode) +{ + m_interpolationType = interpolationMode; +} + +//----------------------------------------------------------------------------- +void WaveForm::setSampleType(SampleType const sampleMode) +{ + m_sampleType = sampleMode; +} + +#ifdef _DEBUG +//----------------------------------------------------------------------------- +std::string const &WaveForm::getName() const +{ + return m_name; +} + +//----------------------------------------------------------------------------- +void WaveForm::setName(std::string const &name) +{ + m_name = name; +} +#endif // _DEBUG + +//----------------------------------------------------------------------------- +void WaveForm::randomize(float const maxValue, float const minValue) +{ + // Remove all the control points + + clear(); + + // Random interpolation mode + + setInterpolationType((rand() % 2) ? IT_linear : IT_spline); + + // Random control positions + + int const count = rand() % 7 + 2; + float const delta = 1.0f / static_cast(count + 1); + + // Start + + insert(WaveFormControlPoint(0.0f, 0.0f, 0.0f, 0.0f)); + + // Inner positions + + for (int i = 0; i < count; ++i) + { + float const fi = static_cast(i); + + float const difference = maxValue - minValue; + float const percent = static_cast((static_cast((delta + delta * fi) * 100.0f)) / 100.0f); + float const value = minValue + (Random::randomReal(0.0f, 1.0f) * difference); + float const randomMax = 0.0f; + float const randomMin = 0.0f; + + insert(WaveFormControlPoint(percent, value, randomMax, randomMin)); + } + + // End + + insert(WaveFormControlPoint(1.0f, 0.0f, 0.0f, 0.0f)); +} + +//----------------------------------------------------------------------------- +float WaveForm::getValue(WaveFormControlPointIter &iter, float const percent) const +{ + if (m_singleValue && + (m_controlPointList.size() > 0)) + { +#ifdef _DEBUG + ++s_singleValueHit; +#endif // _DEBUG + + return (m_controlPointList.begin()->getValue()); + } + +#ifdef _DEBUG + ++s_singleValueMiss; +#endif // _DEBUG + +#ifdef _DEBUG + float const iterPercent = iter.m_iter->m_percent; + UNREF(iterPercent); +#endif // _DEBUG + + DEBUG_FATAL(m_controlPointList.size() < 2, ("WaveForm::getValue() - There must be at least 2 control points defined.")); + DEBUG_FATAL(!verifyIteratorValid(iter.m_iter), ("WaveForm::getValue() - Invalid iterator")); + DEBUG_FATAL(percent < 0.0f, ("WaveForm::getValue() - percent is < 0")); + DEBUG_FATAL(percent > 1.0f, ("WaveForm::getValue() - percent is > 1")); + DEBUG_FATAL(iter.m_iter == m_controlPointList.end(), ("WaveForm::getValue() - iterator == m_controlPointList.end()")); + DEBUG_FATAL(percent < iter.m_iter->m_percent, ("WaveForm::getValue() - percent %f < iter->m_percent %f", percent, iter.m_iter->m_percent)); + + ControlPointList::const_iterator next = iter.m_iter; + ++next; + + if (next != m_controlPointList.end()) + { + float nextPercent = next->m_percent; + + while (percent > nextPercent) + { + ++iter.m_iter; + ++next; + + nextPercent = next->m_percent; + } + } + else + { + next = iter.m_iter; + } + + float const previousPercent = iter.m_iter->m_percent; + float const nextPercent = next->m_percent; + + DEBUG_FATAL((previousPercent > 1.0f), ("previousPercent(%f) > 1", previousPercent)); + DEBUG_FATAL((previousPercent < 0.0f), ("previousPercent(%f) < 0", previousPercent)); + DEBUG_FATAL((nextPercent > 1.0f), ("nextPercent(%f) > 1", nextPercent)); + DEBUG_FATAL((nextPercent < 0.0f), ("nextPercent(%f) < 0", nextPercent)); + + float const previousValue = iter.m_iter->m_value; + float const nextValue = next->m_value; + + float value = previousValue; + + if ((nextPercent - previousPercent) > 0.0f) + { + switch (m_interpolationType) + { + case IT_linear: + { +#ifdef _DEBUG + ++s_linearCalculationCount; +#endif // _DEBUG + + float currentPercent = clamp(0.0f, (percent - previousPercent) / (nextPercent - previousPercent), 1.0f); + + DEBUG_FATAL((currentPercent > 1.0f), ("currentPercent(%f) > 1", currentPercent)); + DEBUG_FATAL((currentPercent < 0.0f), ("currentPercent(%f) < 0", currentPercent)); + + float const valueDifference = (nextValue - previousValue) * currentPercent; + + float const previousRandomMaxValue = iter.m_iter->m_randomMax; + float const previousRandomMinValue = iter.m_iter->m_randomMin; + + float const nextRandomMaxValue = next->m_randomMax; + float const nextRandomMinValue = next->m_randomMin; + + float randomMaxValueDifference = previousRandomMaxValue + (nextRandomMaxValue - previousRandomMaxValue) * currentPercent; + float randomMinValueDifference = previousRandomMinValue + (nextRandomMinValue - previousRandomMinValue) * currentPercent; + + if (m_sampleType == ST_initial) + { + float const randomDifference = randomMaxValueDifference + randomMinValueDifference; + + value += valueDifference - randomMinValueDifference + iter.m_initialPercent * randomDifference; + } + else if (m_sampleType == ST_continuous) + { + value += valueDifference + Random::randomReal(-randomMinValueDifference, randomMaxValueDifference); + } + } + break; + case IT_spline: + { +#ifdef _DEBUG + ++s_splineCalculationCount; +#endif // _DEBUG + + // We have to find the four neighboring control points + + ControlPointList::const_iterator c1 = m_controlPointList.begin(); + ControlPointList::const_iterator c2 = m_controlPointList.begin(); + ControlPointList::const_iterator c3 = m_controlPointList.begin(); + ControlPointList::const_iterator c4 = m_controlPointList.begin(); + + if (m_controlPointList.size() == 2) + { + // Handling 2 controls points is easy + + ++c3; + ++c4; + } + else + { + // Find the correct positions of the control points + + int index = 0; + + for (; c3 != m_controlPointList.end();) + { + ++c3; + c4 = c3; + ++c4; + + if (c4 == m_controlPointList.end()) + { + c4 = c3; + } + + float const previousPercent = c2->getPercent(); + float const currentPercent = c3->getPercent(); + + DEBUG_FATAL((previousPercent > currentPercent), ("WaveForm::getColorAtPercent() - previousPercent(%.3f) > currentPercent(%.3f)", previousPercent, currentPercent)); + + if ((percent >= previousPercent) && + (percent <= currentPercent)) + { + break; + } + else + { + ++c2; + + if (index > 0) + { + ++c1; + } + } + + ++index; + } + } + + // Find the position between the second and third control points + + float const difference = c3->getPercent() - c2->getPercent(); + float const t = (difference > 0.0f) ? ((percent - c2->getPercent()) / difference) : 0.0f; + + DEBUG_FATAL((t < 0.0f), ("WaveForm::getColorAtPercent() - The spline position t(%f) is < 0", t)); + DEBUG_FATAL((t > 1.0f), ("WaveForm::getColorAtPercent() - The spline position t(%f) is > 1", t)); + + // Now that we have found the correct position of the control points, + // we can find the individual color components + + float const c1x = c1->getPercent(); + float const c2x = c2->getPercent(); + float const c3x = c3->getPercent(); + float const c4x = c4->getPercent(); + + // Max value + + float const c1yMax = c1->getValue() + c1->getRandomMax(); + float const c2yMax = c2->getValue() + c2->getRandomMax(); + float const c3yMax = c3->getValue() + c3->getRandomMax(); + float const c4yMax = c4->getValue() + c4->getRandomMax(); + + float resultX; + float maxResultY; + + CatmullRomSpline::getCatmullRomSplinePoint(c1x, c1yMax, c2x, c2yMax, c3x, c3yMax, c4x, c4yMax, t, resultX, maxResultY); + + // Min value + + float const c1yMin = c1->getValue() - c1->getRandomMin(); + float const c2yMin = c2->getValue() - c2->getRandomMin(); + float const c3yMin = c3->getValue() - c3->getRandomMin(); + float const c4yMin = c4->getValue() - c4->getRandomMin(); + + float minResultY; + + CatmullRomSpline::getCatmullRomSplinePoint(c1x, c1yMin, c2x, c2yMin, c3x, c3yMin, c4x, c4yMin, t, resultX, minResultY); + + // Make sure the max is the largest value + + if (minResultY > maxResultY) + { + std::swap(minResultY, maxResultY); + } + + // Get the final value + + if (m_sampleType == ST_initial) + { + value = minResultY + iter.m_initialPercent * (maxResultY - minResultY); + } + else if (m_sampleType == ST_continuous) + { + value = Random::randomReal(minResultY, maxResultY); + } + } + break; + default: + { + DEBUG_FATAL(true, ("Unexpected interpolation mode.")); + } + break; + } + } + + return clamp(m_valueMin, value, m_valueMax); +} + +//----------------------------------------------------------------------------- +void WaveForm::write(Iff &iff) const +{ + iff.insertForm(TAG_WVFM); + { + iff.insertChunk(TAG_0002); + { + iff.insertChunkData(static_cast(m_interpolationType)); + iff.insertChunkData(static_cast(m_sampleType)); + iff.insertChunkData(m_valueMin); + iff.insertChunkData(m_valueMax); + + // Control points + + int32 const controlPointCount = static_cast(m_controlPointList.size()); + + DEBUG_FATAL(controlPointCount < 2, ("There should be 2 or more control points to write.")); + + iff.insertChunkData(controlPointCount); + + ControlPointList::const_iterator current = m_controlPointList.begin(); + + for (; current != m_controlPointList.end(); ++current) + { + float const percent = current->getPercent(); + float const value = current->getValue(); + float const randomMin = current->getRandomMin(); + float const randomMax = current->getRandomMax(); + + iff.insertChunkData(percent); + iff.insertChunkData(value); + iff.insertChunkData(randomMin); + iff.insertChunkData(randomMax); + } + } + iff.exitChunk(TAG_0002); + } + iff.exitForm(TAG_WVFM); +} + +//----------------------------------------------------------------------------- +void WaveForm::load(Iff &iff) +{ + iff.enterForm(TAG_WVFM); + { + switch (iff.getCurrentName()) + { + case TAG_0000: { load_0000(iff); } break; + case TAG_0001: { load_0001(iff); } break; + case TAG_0002: { load_0002(iff); } break; + default: + { + char currentTagName[5]; + ConvertTagToString(iff.getCurrentName(), currentTagName); + + FATAL(true, ("Unsupported data version: %s", currentTagName)); + } + } + } + iff.exitForm(TAG_WVFM); + + DEBUG_FATAL((m_controlPointList.size() < 2), ("Waveforms require at least two control points to be defined. Control points defined: (%d).", m_controlPointList.size())); + +#ifdef _DEBUG + ControlPointList::const_iterator iterControlPointList = m_controlPointList.begin(); + + for (; iterControlPointList != m_controlPointList.end(); ++iterControlPointList) + { + float const percent = iterControlPointList->getPercent(); + + DEBUG_WARNING((percent > 1.0f), ("percent(%f) > 1", percent)); + DEBUG_WARNING((percent < 0.0f), ("percent(%f) < 0", percent)); + } +#endif // _DEBUG + + // Check to see if all the waveform values are just the same, if so, we can make + // some optimazations when querying for waveform values + + m_singleValue = true; + + if (m_controlPointList.size() >= 2) + { + float firstValue = m_controlPointList.begin()->getValue(); + + ControlPointList::const_iterator iterControlPointList = m_controlPointList.begin(); + ++iterControlPointList; + + for (; iterControlPointList != m_controlPointList.end(); ++iterControlPointList) + { + float const currentValue = iterControlPointList->getValue(); + float const randomMin = iterControlPointList->getRandomMin(); + float const randomMax = iterControlPointList->getRandomMax(); + + if ((currentValue != firstValue) || + ((currentValue == firstValue) && + ((randomMin != 0.0f) || + (randomMax != 0.0f)))) + { + m_singleValue = false; + break; + } + } + } +} + +//----------------------------------------------------------------------------- +void WaveForm::load_0000(Iff &iff) +{ + m_controlPointList.clear(); + + iff.enterChunk(TAG_0000); + { + // Interpolation mode + + m_interpolationType = static_cast(iff.read_int32()); + + // Control points + + int const controlPointCount = iff.read_int32(); + + for (int i = 0; i < controlPointCount; ++i) + { + float const percent = iff.read_float(); + float const value = iff.read_float(); + float const randomMax = iff.read_float(); + float const randomMin = iff.read_float(); + + WaveFormControlPoint controlPoint(percent, value, randomMax, randomMin); + + insert(controlPoint); + } + } + iff.exitChunk(TAG_0000); +} + +//----------------------------------------------------------------------------- +void WaveForm::load_0001(Iff &iff) +{ + m_controlPointList.clear(); + + iff.enterChunk(TAG_0001); + { + // Interpolation mode + + m_interpolationType = static_cast(iff.read_int32()); + + // Sample mode + + m_sampleType = static_cast(iff.read_int32()); + + // Control points + + int const controlPointCount = iff.read_int32(); + + for (int i = 0; i < controlPointCount; ++i) + { + float const percent = iff.read_float(); + float const value = iff.read_float(); + float const randomMax = iff.read_float(); + float const randomMin = iff.read_float(); + + WaveFormControlPoint controlPoint(percent, value, randomMax, randomMin); + + insert(controlPoint); + } + } + iff.exitChunk(TAG_0001); +} + +//----------------------------------------------------------------------------- +void WaveForm::load_0002(Iff & iff) +{ + m_controlPointList.clear(); + + iff.enterChunk(TAG_0002); + { + m_interpolationType = static_cast(iff.read_int32()); + m_sampleType = static_cast(iff.read_int32()); + m_valueMin = iff.read_float(); + m_valueMax = iff.read_float(); + + // Control points + + int const controlPointCount = iff.read_int32(); + + for (int i = 0; i < controlPointCount; ++i) + { + float const percent = iff.read_float(); + float const value = iff.read_float(); + float const randomMin = iff.read_float(); + float const randomMax = iff.read_float(); + + WaveFormControlPoint controlPoint(percent, value, randomMax, randomMin); + + insert(controlPoint); + } + } + iff.exitChunk(TAG_0002); +} + +//----------------------------------------------------------------------------- +WaveForm::ControlPointList::iterator WaveForm::getIteratorBegin() +{ + return m_controlPointList.begin(); +} + +//----------------------------------------------------------------------------- +WaveForm::ControlPointList::iterator WaveForm::getIteratorEnd() +{ + return m_controlPointList.end(); +} + +//----------------------------------------------------------------------------- +WaveForm::ControlPointList::const_iterator WaveForm::getIteratorBegin() const +{ + return m_controlPointList.begin(); +} + +//----------------------------------------------------------------------------- +WaveForm::ControlPointList::const_iterator WaveForm::getIteratorEnd() const +{ + return m_controlPointList.end(); +} + +//----------------------------------------------------------------------------- +int WaveForm::getControlPointCount() const +{ + return static_cast(m_controlPointList.size()); +} + +//----------------------------------------------------------------------------- +void WaveForm::clampAll(float const min, float const max) +{ + setValueMin(min); + setValueMax(max); + + ControlPointList::iterator current = m_controlPointList.begin(); + + for (; current != m_controlPointList.end(); ++current) + { + clampValue(*current); + } +} + +//----------------------------------------------------------------------------- +void WaveForm::scaleAll(float const percent) +{ + ControlPointList::iterator current = m_controlPointList.begin(); + + for (; current != m_controlPointList.end(); ++current) + { + float const newPercent = current->getPercent(); + float const newValue = current->getValue() * percent; + float const newRandomMin = current->getRandomMin() * percent; + float const newRandomMax = current->getRandomMax() * percent; + + *current = WaveFormControlPoint(newPercent, newValue, newRandomMax, newRandomMin); + } +} + +#ifdef _DEBUG +//----------------------------------------------------------------------------- +bool WaveForm::verifyIteratorValid(ControlPointList::const_iterator const &iter) const +{ + bool result = false; + ControlPointList::const_iterator current = m_controlPointList.begin(); + + for (; current != m_controlPointList.end(); ++current) + { + if (current == iter) + { + result = true; + break; + } + } + + return result; +} +#endif // _DEBUG + +//----------------------------------------------------------------------------- + +bool WaveForm::isConstantValue(float const val) +{ + if(!m_singleValue) + return false; + if(m_controlPointList.empty()) + return true; + WaveFormControlPoint &firstPoint = *(m_controlPointList.begin()); + return (WithinEpsilonInclusive(firstPoint.m_value, val, 0.00001f) && + WithinEpsilonInclusive(firstPoint.m_randomMin, 0.0f, 0.00001f) && + WithinEpsilonInclusive(firstPoint.m_randomMax, 0.0f, 0.00001f)); +} + +// ============================================================================ diff --git a/engine/shared/library/sharedMath/src/shared/WaveForm.h b/engine/shared/library/sharedMath/src/shared/WaveForm.h new file mode 100644 index 00000000..c5c8d2c5 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/WaveForm.h @@ -0,0 +1,218 @@ +// ============================================================================ +// +// WaveForm.h +// Copyright Sony Online Entertainment +// +// ============================================================================ + +#ifndef INCLUDED_WaveForm_H +#define INCLUDED_WaveForm_H + +#include +#include + +class WaveForm; +class WaveFormControlPointIter; // Defined below +class WaveFormEdit; +class Iff; + +//----------------------------------------------------------------------------- +class WaveFormControlPoint +{ +friend class WaveForm; + +public: + + WaveFormControlPoint(); + WaveFormControlPoint(float const percent, float const value, float const randomMax = 0.0f, float const randomMin = 0.0f); + + void setValue(float const value); + void setRandomMin(float const randomMin); + void setRandomMax(float const randomMax); + + float getPercent() const; + float getValue() const; + float getRandomMin() const; + float getRandomMax() const; + +private: + + float m_percent; // [0..1] + float m_value; // [-n..n] + float m_randomMax; // [0..n] + float m_randomMin; // [0..n] + static float const m_theValueMax; + static float const m_theValueMin; +}; + +//----------------------------------------------------------------------------- +class WaveForm +{ +public: + + typedef std::list ControlPointList; + + enum InterpolationType + { + IT_linear, + IT_spline, + }; + + enum SampleType + { + ST_initial, + ST_continuous, + }; + +#ifdef _DEBUG + static int getSingleValueHit(); + static int getSingleValueMiss(); + static int getSplineCalculationCount(); + static int getLinearCalculationCount(); +#endif // _DEBUG + +public: + + WaveForm(); + WaveForm(WaveForm const &rhs); + ~WaveForm(); + + WaveForm & operator =(WaveForm const &rhs); + +#ifdef _DEBUG + // Set/get the name + + std::string const &getName() const; + void setName(std::string const &name); +#endif // _DEBUG + + // Get the interpolated value + + float getValue(WaveFormControlPointIter &iter, float const percent) const; + + // Set/Get the max and min values + + void setValueMax(float const max); + void setValueMin(float const min); + float const getValueMax() const; + float const getValueMin() const; + + // Copies all the data except the min and max, so the inserted data is clamped + // to the current min and max + + void copyControlPoints(WaveForm const &waveForm); + + // Calculates the min and max control point value + + void calculateMinMax(float &max, float &min); + + // Adds the control point into the correct place in the list based on the percent + + void insert(WaveFormControlPoint const &controlPoint); + + // Remove a control point from the waveform + + void remove(ControlPointList::iterator &iter); + + // Changes the values of the control point at the iterator + + void setControlPoint(ControlPointList::const_iterator const &iter, WaveFormControlPoint const &controlPoint); + + // Scales all the control points by the specified percent + + void scaleAll(float const percent); + + // Change the interpolation type + + void setInterpolationType(InterpolationType const interpolationType); + + // Change the sample type + + void setSampleType(SampleType const sampleType); + + // Remove all the control points + + void clear(); + + // Set some random values at a random number of control points + + void randomize(float const maxValue = 1.0f, float const minValue = 0.0f); + + // Load the waveform from an iff + + void load(Iff &iff); + + // Write the waveform to an iff + + void write(Iff &iff) const; + + // Get the begin and end iterator from the control point list + + ControlPointList::iterator getIteratorBegin(); + ControlPointList::iterator getIteratorEnd(); + ControlPointList::const_iterator getIteratorBegin() const; + ControlPointList::const_iterator getIteratorEnd() const; + + // Get the number of control points in the list + + int getControlPointCount() const; + + // Get the interpolation type + + InterpolationType getInterpolationType() const; + + // Get the sample type + + SampleType getSampleType() const; + + void clampAll(float const min, float const max); + + bool isConstantValue(float const val); +private: + + ControlPointList m_controlPointList; + InterpolationType m_interpolationType; + SampleType m_sampleType; + float m_valueMax; + float m_valueMin; + bool m_singleValue; + + // Assures the value is between the maxValue and the minValue + + void clampValue(WaveFormControlPoint &controlPoint) const; + + // Assures the percent value of the control point is valid, relative to + // the neighboring control points + + void clampPercent(ControlPointList::iterator const &iter); + + void load_0000(Iff &iff); + void load_0001(Iff &iff); + void load_0002(Iff & iff); + +#ifdef _DEBUG + std::string m_name; + int m_controlPointCount; + + // Verifies the iterator belongs to this waveform + + bool verifyIteratorValid(ControlPointList::const_iterator const &iter) const; +#endif // _DEBUG +}; + +//----------------------------------------------------------------------------- +class WaveFormControlPointIter +{ +public: + + WaveFormControlPointIter(); + + void reset(WaveForm::ControlPointList::const_iterator const &iter); + + WaveForm::ControlPointList::const_iterator m_iter; + float m_initialPercent; // [0..1] +}; + +// ============================================================================ + +#endif // INCLUDED_WaveForm_H diff --git a/engine/shared/library/sharedMath/src/shared/WaveForm3D.cpp b/engine/shared/library/sharedMath/src/shared/WaveForm3D.cpp new file mode 100644 index 00000000..11c20bd0 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/WaveForm3D.cpp @@ -0,0 +1,71 @@ +// ============================================================================ +// +// WaveForm3D.cpp +// Copyright Sony Online Entertainment +// +// ============================================================================ + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/WaveForm3D.h" + +//----------------------------------------------------------------------------- + +WaveForm3D::WaveForm3D() +: m_xWaveForm(WaveForm()) +, m_yWaveForm(WaveForm()) +, m_zWaveForm(WaveForm()) +, m_xWaveIterator(WaveFormControlPointIter()) +, m_yWaveIterator(WaveFormControlPointIter()) +, m_zWaveIterator(WaveFormControlPointIter()) +, m_isDirty(true) +{ +} + +//----------------------------------------------------------------------------- + +WaveForm3D::~WaveForm3D() +{ +} + +//----------------------------------------------------------------------------- + +void WaveForm3D::insert(float const time, Vector const & controlPoint) +{ + VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(0.0f, time, 1.0f); + + m_xWaveForm.insert(WaveFormControlPoint(time, controlPoint.x)); + m_yWaveForm.insert(WaveFormControlPoint(time, controlPoint.y)); + m_zWaveForm.insert(WaveFormControlPoint(time, controlPoint.z)); + + m_isDirty = true; +} + +//----------------------------------------------------------------------------- + +/** + * Get the value at a paricular point in time + * @param time the time + * @param point (output) the point + * @param randomOrder Set this to true if this function will be called with + * values for "time" that are not in increasing order + */ +void WaveForm3D::getValue(float const time, Vector & point, bool randomOrder) +{ + VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(0.0f, time, 1.0f); + + if (m_isDirty || randomOrder) + { + m_xWaveIterator.reset(m_xWaveForm.getIteratorBegin()); + m_yWaveIterator.reset(m_yWaveForm.getIteratorBegin()); + m_zWaveIterator.reset(m_zWaveForm.getIteratorBegin()); + m_isDirty = false; + } + + float const x = m_xWaveForm.getValue(m_xWaveIterator, time); + float const y = m_yWaveForm.getValue(m_yWaveIterator, time); + float const z = m_zWaveForm.getValue(m_zWaveIterator, time); + + point.set(x, y, z); +} + +// ============================================================================ diff --git a/engine/shared/library/sharedMath/src/shared/WaveForm3D.h b/engine/shared/library/sharedMath/src/shared/WaveForm3D.h new file mode 100644 index 00000000..162048f7 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/WaveForm3D.h @@ -0,0 +1,67 @@ +// ============================================================================ +// +// WaveForm3D.h +// Copyright Sony Online Entertainment +// +// ============================================================================ + +#ifndef INCLUDED_WaveForm3D_H +#define INCLUDED_WaveForm3D_H + +//------------------------------------------------------------------- + +#include "sharedMath/WaveForm.h" +#include "sharedMath/Vector.h" + +//------------------------------------------------------------------- +// +// Simple wrapper class to the WaveForm class to manage points in 3D space +// +// Usage: +// +// WaveForm3D waveForm; +// +// // Initialize the data that the waveform can work with +// +// waveForm.insert(0.0f, Vector(0.0f, 0.0f, 0.0f)); // time must be [0.0f .. 1.0f] +// waveForm.insert(0.25f, Vector(0.0f, 0.0f, 5.0f)); +// waveForm.insert(0.5f, Vector(0.0f, 0.0f, 10.0f)); +// waveForm.insert(0.75f, Vector(0.0f, 0.0f, 15.0f)); +// waveForm.insert(1.0f, Vector(0.0f, 0.0f, 20.0f)); +// +// . +// . +// . +// +// // at a later time extract the interpolated result +// +// float const time = 0.2358f; //must be [0.0f .. 1.0f] +// Vector pointAtTime; +// +// waveForm.getValue(time, pointAtTime); +// +//------------------------------------------------------------------- + +class WaveForm3D +{ +public: + + WaveForm3D(); + ~WaveForm3D(); + + void insert(float const time, Vector const & controlPoint); + void getValue(float const time, Vector & point, bool randomOrder = false); + +private: + WaveForm m_xWaveForm; + WaveForm m_yWaveForm; + WaveForm m_zWaveForm; + + WaveFormControlPointIter m_xWaveIterator; + WaveFormControlPointIter m_yWaveIterator; + WaveFormControlPointIter m_zWaveIterator; + + bool m_isDirty; +}; + +#endif diff --git a/engine/shared/library/sharedMath/src/shared/core/AxialBox.cpp b/engine/shared/library/sharedMath/src/shared/core/AxialBox.cpp new file mode 100644 index 00000000..0beb7f61 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/AxialBox.cpp @@ -0,0 +1,174 @@ +// ====================================================================== +// +// AxialBox.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/AxialBox.h" + +#include "sharedMath/Range.h" + +#include // for min/max +#include // for min/max + +// ====================================================================== + +AxialBox::AxialBox() : + m_min( Vector::maxXYZ ), + m_max( Vector::negativeMaxXYZ ) +{ +} + +AxialBox::AxialBox ( Vector const & cornerA, Vector const & cornerB ) +{ + if (cornerA.x < cornerB.x) + { + m_min.x = cornerA.x; + m_max.x = cornerB.x; + } + else + { + m_min.x = cornerB.x; + m_max.x = cornerA.x; + } + if (cornerA.y < cornerB.y) + { + m_min.y = cornerA.y; + m_max.y = cornerB.y; + } + else + { + m_min.y = cornerB.y; + m_max.y = cornerA.y; + } + if (cornerA.z < cornerB.z) + { + m_min.z = cornerA.z; + m_max.z = cornerB.z; + } + else + { + m_min.z = cornerB.z; + m_max.z = cornerA.z; + } +} + +AxialBox::AxialBox( Range const & rX, Range const & rY, Range const & rZ ) +: m_min(rX.getMin(),rY.getMin(),rZ.getMin()), + m_max(rX.getMax(),rY.getMax(),rZ.getMax()) +{ +} + +AxialBox::AxialBox( AxialBox const & boxA, AxialBox const & boxB ) +: m_min( boxA.getMin() ), + m_max( boxA.getMax() ) +{ + add(boxB); +} + +// ---------------------------------------------------------------------- + +void AxialBox::clear ( void ) +{ + m_min = Vector::maxXYZ; + m_max = Vector::negativeMaxXYZ; +} + +void AxialBox::add ( Vector const & V ) +{ + if (m_min.x > m_max.x) + { + addMin(V); + addMax(V); + } + else + { + if (V.x < m_min.x) + m_min.x = V.x; + else if (V.x > m_max.x) + m_max.x = V.x; + + if (V.y < m_min.y) + m_min.y = V.y; + else if (V.y > m_max.y) + m_max.y = V.y; + + if (V.z < m_min.z) + m_min.z = V.z; + else if (V.z > m_max.z) + m_max.z = V.z; + } +} + +void AxialBox::addMin ( Vector const & V ) +{ + if (V.x < m_min.x) + m_min.x = V.x; + + if (V.y < m_min.y) + m_min.y = V.y; + + if (V.z < m_min.z) + m_min.z = V.z; +} + +void AxialBox::addMax ( Vector const & V ) +{ + if (V.x > m_max.x) + m_max.x = V.x; + + if (V.y > m_max.y) + m_max.y = V.y; + + if (V.z > m_max.z) + m_max.z = V.z; +} + +void AxialBox::add ( std::vector const & vertices ) +{ + VertexList::const_iterator const iEnd = vertices.end(); + for (VertexList::const_iterator i = vertices.begin(); i != iEnd; ++i) + add(*i); +} + +void AxialBox::add ( AxialBox const & A ) +{ + addMin(A.getMin()); + addMax(A.getMax()); +} + +bool AxialBox::contains ( Vector const & V ) const +{ + if( V.z < m_min.z ) return false; + if( V.x < m_min.x ) return false; + if( V.y < m_min.y ) return false; + + if( V.z > m_max.z ) return false; + if( V.x > m_max.x ) return false; + if( V.y > m_max.y ) return false; + + return true; +} + +bool AxialBox::contains ( AxialBox const & A ) const +{ + return contains ( A.m_min ) && contains ( A.m_max ); +} + +bool AxialBox::isEmpty ( void ) const +{ + // All should be valid if we have initialized it at all. + return m_min.x > m_max.x; +} + +Range AxialBox::getRangeX ( void ) const { return Range(m_min.x,m_max.x); } +Range AxialBox::getRangeY ( void ) const { return Range(m_min.y,m_max.y); } +Range AxialBox::getRangeZ ( void ) const { return Range(m_min.z,m_max.z); } + +bool AxialBox::intersects (const AxialBox& other) const +{ + return !(m_max.x < other.m_min.x || m_min.x > other.m_max.x || m_max.y < other.m_min.y || m_min.y > other.m_max.y || m_max.z < other.m_min.z || m_min.z > other.m_max.z); +} + diff --git a/engine/shared/library/sharedMath/src/shared/core/AxialBox.h b/engine/shared/library/sharedMath/src/shared/core/AxialBox.h new file mode 100644 index 00000000..83fc6a18 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/AxialBox.h @@ -0,0 +1,180 @@ +// ====================================================================== +// +// AxialBox.h +// copyright (c) 2001 Sony Online Entertainment +// +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_AxialBox_H +#define INCLUDED_AxialBox_H + +#include "sharedMath/Vector.h" + +class Range; + +// ====================================================================== + +class AxialBox +{ +public: + + typedef stdvector::fwd VertexList; + +public: + + AxialBox(); + AxialBox( Vector const & cornerA, Vector const & cornerB ); + AxialBox( Range const & rX, Range const & rY, Range const & rZ ); + AxialBox( AxialBox const & boxA, AxialBox const & boxB ); + + void clear ( void ); + void add ( Vector const & V ); + void addMin ( Vector const & V ); + void addMax ( Vector const & V ); + void add ( VertexList const & vertices ); + void add ( AxialBox const & A ); + bool contains ( Vector const & V ) const; + bool contains ( AxialBox const & A ) const; + bool isEmpty ( void ) const; + + // ---------- + + Vector const & getMin ( void ) const; + Vector const & getMax ( void ) const; + + void setMin ( Vector const & newMin ); + void setMax ( Vector const & newMax ); + + real getWidth ( void ) const; + real getHeight ( void ) const; + real getDepth ( void ) const; + + Vector getSize ( void ) const; + Vector getCenter ( void ) const; + Vector getDelta ( void ) const; + + real getRadius ( void ) const; + float getRadiusSquared() const; + + Range getRangeX ( void ) const; + Range getRangeY ( void ) const; + Range getRangeZ ( void ) const; + + Vector getBase ( void ) const; + + Vector getCorner ( int whichCorner ) const; + + real getVolume ( void ) const; + real getArea ( void ) const; + + // ---------- + + Vector const & getAxisX ( void ) const; + Vector const & getAxisY ( void ) const; + Vector const & getAxisZ ( void ) const; + + float getExtentX ( void ) const; + float getExtentY ( void ) const; + float getExtentZ ( void ) const; + + bool intersects ( AxialBox const & other ) const; + +protected: + + Vector m_min; + Vector m_max; +}; + +// ---------------------------------------------------------------------- + +inline Vector const & AxialBox::getMin ( void ) const { return m_min; } +inline Vector const & AxialBox::getMax ( void ) const { return m_max; } + +inline void AxialBox::setMin ( Vector const & newMin ) { m_min = newMin; } +inline void AxialBox::setMax ( Vector const & newMax ) { m_max = newMax; } + +inline real AxialBox::getWidth ( void ) const { return m_max.x - m_min.x; } +inline real AxialBox::getHeight ( void ) const { return m_max.y - m_min.y; } +inline real AxialBox::getDepth ( void ) const { return m_max.z - m_min.z; } + +inline Vector AxialBox::getSize ( void ) const { return (m_max - m_min); } +inline Vector AxialBox::getCenter ( void ) const { return (m_max + m_min) / 2.0f; } +inline Vector AxialBox::getDelta ( void ) const { return (m_max - m_min) / 2.0f; } + +inline real AxialBox::getRadius ( void ) const { return getDelta().magnitude(); } +inline float AxialBox::getRadiusSquared() const +{ + return getDelta().magnitudeSquared(); +} + +inline Vector AxialBox::getBase ( void ) const { return Vector( (m_min.x + m_max.x) / 2.0f, m_min.y, (m_min.z + m_max.z) / 2.0f ); } + +inline Vector AxialBox::getCorner ( int whichCorner ) const +{ + // These corners are ordered so that the first 4 are on the bottom of the box + + switch(whichCorner) + { + case 0: return Vector( m_min.x, m_min.y, m_min.z ); + case 1: return Vector( m_max.x, m_min.y, m_min.z ); + case 2: return Vector( m_min.x, m_min.y, m_max.z ); + case 3: return Vector( m_max.x, m_min.y, m_max.z ); + case 4: return Vector( m_min.x, m_max.y, m_min.z ); + case 5: return Vector( m_max.x, m_max.y, m_min.z ); + case 6: return Vector( m_min.x, m_max.y, m_max.z ); + case 7: return Vector( m_max.x, m_max.y, m_max.z ); + + default: return Vector(0,0,0); + } +} + +inline float AxialBox::getVolume ( void ) const +{ + return (m_max.x - m_min.x) * (m_max.y - m_min.y) * (m_max.z - m_min.z); +} + +inline float AxialBox::getArea ( void ) const +{ + Vector V = getSize(); + + return ((V.x * V.y) + (V.y * V.z) + (V.z * V.x)) * 2.0f; +} + +// ---------------------------------------------------------------------- + +inline Vector const & AxialBox::getAxisX ( void ) const +{ + return Vector::unitX; +} + +inline Vector const & AxialBox::getAxisY ( void ) const +{ + return Vector::unitY; +} + +inline Vector const & AxialBox::getAxisZ ( void ) const +{ + return Vector::unitZ; +} + +// ---------- + +inline float AxialBox::getExtentX ( void ) const +{ + return (m_max.x - m_min.x) / 2.0f; +} + +inline float AxialBox::getExtentY ( void ) const +{ + return (m_max.y - m_min.y) / 2.0f; +} + +inline float AxialBox::getExtentZ ( void ) const +{ + return (m_max.z - m_min.z) / 2.0f; +} + +// ---------------------------------------------------------------------- + +#endif + diff --git a/engine/shared/library/sharedMath/src/shared/core/Capsule.cpp b/engine/shared/library/sharedMath/src/shared/core/Capsule.cpp new file mode 100644 index 00000000..f8e8656b --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Capsule.cpp @@ -0,0 +1,11 @@ +// ====================================================================== +// +// Capsule.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/Capsule.h" + + diff --git a/engine/shared/library/sharedMath/src/shared/core/Capsule.h b/engine/shared/library/sharedMath/src/shared/core/Capsule.h new file mode 100644 index 00000000..4a31e74b --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Capsule.h @@ -0,0 +1,174 @@ +// ====================================================================== +// +// Capsule.h +// copyright (c) 2001 Sony Online Entertainment +// +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_Capsule_H +#define INCLUDED_Capsule_H + +#include "sharedMath/Vector.h" +#include "sharedMath/Sphere.h" + +// ---------------------------------------------------------------------- + +class Capsule +{ +public: + + Capsule ( Vector const & A, Vector const & B, float radius ); + + Capsule ( Sphere const & A, Vector const & delta ); + + Vector const & getPointA ( void ) const; + Vector const & getPointB ( void ) const; + + float const & getRadius ( void ) const; + + // ---------- + + Vector getCenter ( void ) const; + float getTotalRadius ( void ) const; + + Sphere getBoundingSphere ( void ) const; + + Sphere getSphereA ( void ) const; + Sphere getSphereB ( void ) const; + + Vector getDelta ( void ) const; + + // ---------- + + bool contains ( Sphere const & S ) const; + bool intersectsSphere ( Sphere const & S ) const; + +protected: + + Vector m_pointA; + Vector m_pointB; + float m_radius; + + // These two values help accelerate sphere tree queries + + Vector m_normal; + float m_segmentLength; +}; + +// ---------- + +inline Capsule::Capsule ( Vector const & A, Vector const & B, float radius ) +: m_pointA(A), m_pointB(B), m_radius(radius) +{ + Vector delta = B - A; + + m_segmentLength = delta.magnitude(); + + if(m_segmentLength > 0.0f) + { + m_normal = delta / m_segmentLength; + } + else + { + m_normal = Vector::zero; + } +} + +inline Capsule::Capsule ( Sphere const & S, Vector const & delta ) +: m_pointA(S.getCenter()), + m_pointB(S.getCenter() + delta), + m_radius(S.getRadius()) +{ + m_segmentLength = delta.magnitude(); + + if(m_segmentLength > 0.0f) + { + m_normal = delta / m_segmentLength; + } + else + { + m_normal = Vector::zero; + } +} + +inline Vector const & Capsule::getPointA ( void ) const +{ + return m_pointA; +} + +inline Vector const & Capsule::getPointB ( void ) const +{ + return m_pointB; +} + +inline float const & Capsule::getRadius ( void ) const +{ + return m_radius; +} + +inline Vector Capsule::getCenter ( void ) const +{ + return (m_pointA + m_pointB) / 2.0f; +} + +inline float Capsule::getTotalRadius ( void ) const +{ + return m_radius + (m_segmentLength / 2.0f); +} + +inline Sphere Capsule::getBoundingSphere ( void ) const +{ + return Sphere(getCenter(),getTotalRadius()); +} + +// ---------- + +inline Sphere Capsule::getSphereA ( void ) const +{ + return Sphere(m_pointA,m_radius); +} + +inline Sphere Capsule::getSphereB ( void ) const +{ + return Sphere(m_pointB,m_radius); +} + +inline Vector Capsule::getDelta ( void ) const +{ + return m_pointB - m_pointA; +} + +// ---------------------------------------------------------------------- + +inline bool Capsule::contains ( Sphere const & S ) const +{ + if(m_radius < S.getRadius()) return false; + + Vector D = S.getCenter() - m_pointA; + + float t = clamp(0.0f, D.dot(m_normal), m_segmentLength); + + float diff2 = sqr(m_radius - S.getRadius()); + + float dist2 = D.magnitudeBetweenSquared(m_normal * t); + + return dist2 < diff2; +} + +inline bool Capsule::intersectsSphere ( Sphere const & S ) const +{ + Vector D = S.getCenter() - m_pointA; + + float t = clamp(0.0f, D.dot(m_normal), m_segmentLength); + + float sum2 = sqr(m_radius + S.getRadius()); + + float dist2 = D.magnitudeBetweenSquared(m_normal * t); + + return dist2 < sum2; +} + +// ---------------------------------------------------------------------- + +#endif // #ifndef INCLUDED_Capsule_H + diff --git a/engine/shared/library/sharedMath/src/shared/core/Circle.cpp b/engine/shared/library/sharedMath/src/shared/core/Circle.cpp new file mode 100644 index 00000000..44159dd2 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Circle.cpp @@ -0,0 +1,34 @@ +// ====================================================================== +// +// Circle.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/Circle.h" + +#include "sharedMath/Plane3d.h" +#include "sharedMath/Range.h" + +Range Circle::getRangeX ( void ) const +{ + return Range( m_center.x - m_radius, m_center.x + m_radius ); +} + +Range Circle::getRangeZ ( void ) const +{ + return Range( m_center.z - m_radius, m_center.z + m_radius ); +} + +Range Circle::getLocalRangeX ( void ) const +{ + return Range( -m_radius, m_radius ); +} + +Plane3d Circle::getPlane ( void ) const +{ + return Plane3d(m_center,Vector::unitY); +} + + diff --git a/engine/shared/library/sharedMath/src/shared/core/Circle.h b/engine/shared/library/sharedMath/src/shared/core/Circle.h new file mode 100644 index 00000000..4964fc15 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Circle.h @@ -0,0 +1,92 @@ +// ====================================================================== +// +// Circle.h +// copyright (c) 2001 Sony Online Entertainment +// +// Simple class to represent a 2D circle in the X-Z plane +// +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_Circle_H +#define INCLUDED_Circle_H + +#include "sharedMath/Vector.h" + +class Range; +class Plane3d; + +// ====================================================================== + +class Circle +{ +public: + + Circle ( Vector const & center, float radius ); + + // ---------- + + Vector const & getCenter ( void ) const; + void setCenter ( Vector const & center ); + + float getRadius ( void ) const; + void setRadius ( float radius ); + + float getRadiusSquared ( void ) const; + + Range getRangeX ( void ) const; + Range getRangeZ ( void ) const; + + Range getLocalRangeX ( void ) const; + + Plane3d getPlane ( void ) const; + +protected: + + Vector m_center; + float m_radius; +}; + +// ---------------------------------------------------------------------- + +inline Circle::Circle ( Vector const & center, float radius ) +: m_center(center), + m_radius(radius) +{ + +} + +// ---------- + +inline Vector const & Circle::getCenter ( void ) const +{ + return m_center; +} + +inline void Circle::setCenter ( Vector const & center ) +{ + m_center = center; +} + +// ---------- + +inline float Circle::getRadius ( void ) const +{ + return m_radius; +} + +inline void Circle::setRadius ( float radius ) +{ + m_radius = radius; +} + +// ---------- + +inline float Circle::getRadiusSquared ( void ) const +{ + return m_radius * m_radius; +} + +// ---------------------------------------------------------------------- + +#endif + diff --git a/engine/shared/library/sharedMath/src/shared/core/Cylinder.cpp b/engine/shared/library/sharedMath/src/shared/core/Cylinder.cpp new file mode 100644 index 00000000..c2892eb9 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Cylinder.cpp @@ -0,0 +1,39 @@ +// ====================================================================== +// +// Cylinder.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/Cylinder.h" + +#include "sharedMath/Circle.h" +#include "sharedMath/Range.h" +#include "sharedMath/Ring.h" + +Ring Cylinder::getTopRing ( void ) const +{ + return Ring( Vector(m_base.x, m_base.y + m_height, m_base.z), m_radius ); +} + +Ring Cylinder::getBaseRing ( void ) const +{ + return Ring( m_base, m_radius ); +} + +Range Cylinder::getRangeY ( void ) const +{ + return Range( m_base.y, m_base.y + m_height ); +} + +Circle Cylinder::getTopCircle ( void ) const +{ + return Circle( Vector(m_base.x, m_base.y + m_height, m_base.z), m_radius ); +} + +Circle Cylinder::getBaseCircle ( void ) const +{ + return Circle( m_base, m_radius ); +} + diff --git a/engine/shared/library/sharedMath/src/shared/core/Cylinder.h b/engine/shared/library/sharedMath/src/shared/core/Cylinder.h new file mode 100644 index 00000000..5df3992b --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Cylinder.h @@ -0,0 +1,160 @@ +// ====================================================================== +// +// Cylinder.h +// copyright (c) 2001 Sony Online Entertainment +// +// Very, very simple Y-axis aligned cylinder used for simple collision +// +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_Cylinder_H +#define INCLUDED_Cylinder_H + +#include "sharedMath/Vector.h" + +class Range; +class Circle; +class Ring; + +// ====================================================================== + +class Cylinder +{ +public: + + Cylinder(); + Cylinder( Vector const & base, real radius, real height ); + + Vector const & getBase ( void ) const; + float getRadius ( void ) const; + float getHeight ( void ) const; + + void setBase ( Vector const & newBase ); + void setRadius ( real newRadius ); + void setHeight ( real newHeight ); + + // ---------- + // Helper methods for MultiShape + + Vector getCenter ( void ) const; + + Vector const & getAxisX ( void ) const; + Vector const & getAxisY ( void ) const; + Vector const & getAxisZ ( void ) const; + + float getExtentX ( void ) const; + float getExtentY ( void ) const; + float getExtentZ ( void ) const; + + // ---------- + + Range getRangeY ( void ) const; + + Circle getTopCircle ( void ) const; + Circle getBaseCircle ( void ) const; + + Ring getTopRing ( void ) const; + Ring getBaseRing ( void ) const; + +protected: + + Vector m_base; + float m_radius; + float m_height; +}; + +// ---------------------------------------------------------------------- + +inline Cylinder::Cylinder() +: m_base( Vector::zero ), + m_radius( 1.0f ), + m_height( 1.0f ) +{ +} + +inline Cylinder::Cylinder ( Vector const & base, real radius, real height ) +: m_base(base), + m_radius(radius), + m_height(height) +{ +} + +// ---------------------------------------------------------------------- + +inline Vector const & Cylinder::getBase ( void ) const +{ + return m_base; +} + +inline float Cylinder::getRadius ( void ) const +{ + return m_radius; +} + +inline float Cylinder::getHeight ( void ) const +{ + return m_height; +} + +// ---------------------------------------------------------------------- + +inline void Cylinder::setBase ( Vector const & newBase ) +{ + m_base = newBase; +} + +inline void Cylinder::setRadius ( real newRadius ) +{ + m_radius = newRadius; +} + +inline void Cylinder::setHeight ( real newHeight ) +{ + m_height = newHeight; +} + +// ---------------------------------------------------------------------- + +inline Vector Cylinder::getCenter ( void ) const +{ + return m_base + Vector( 0.0f, m_height / 2.0f, 0.0f ); +} + +// ---------- + +inline Vector const & Cylinder::getAxisX ( void ) const +{ + return Vector::unitX; +} + +inline Vector const & Cylinder::getAxisY ( void ) const +{ + return Vector::unitY; +} + +inline Vector const & Cylinder::getAxisZ ( void ) const +{ + return Vector::unitZ; +} + +// ---------- + +inline float Cylinder::getExtentX ( void ) const +{ + return getRadius(); +} + +inline float Cylinder::getExtentY ( void ) const +{ + return getHeight() / 2.0f; +} + +inline float Cylinder::getExtentZ ( void ) const +{ + return getRadius(); +} + +// ---------------------------------------------------------------------- + +#endif // #ifdef INCLUDED_Cylinder_H + diff --git a/engine/shared/library/sharedMath/src/shared/core/Hsv.cpp b/engine/shared/library/sharedMath/src/shared/core/Hsv.cpp new file mode 100644 index 00000000..b7a1d3d6 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Hsv.cpp @@ -0,0 +1,80 @@ +// ====================================================================== +// +// Hsv.cpp +// copyright 2005 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/Hsv.h" + +#include "sharedMath/Vector.h" +#include "sharedMath/VectorArgb.h" +#include "sharedMath/VectorRgba.h" + +#include + +// ====================================================================== + +void Hsv::rgbToHsv(float const red, float const green, float const blue, float &hue, float &saturation, float &value) +{ + float const min = std::min(red, std::min(green, blue)); + float const max = std::max(red, std::max(green, blue)); + float const delta = (max - min); + + hue = 0.0f; + saturation = 0.0f; + value = max; + + if (max > 0.0f) + { + saturation = delta / max; + } + else + { + hue = -1.0f; + + return; + } + + if (delta > 0.0f) + { + if (WithinEpsilonInclusive(red, max, 0.0001f)) + { + hue = (green - blue) / delta; // between yellow and magenta + } + else if (WithinEpsilonInclusive(green, max, 0.0001f)) + { + hue = 2.0f + (blue - red) / delta; // between cyan and yellow + } + else + { + hue = 4.0f + (red - green) / delta; // between magenta and cyan + } + } + + hue *= 60.0f; // degrees + + if (hue < 0.0f) + { + hue += 360.0f; + } +} + +// ---------------------------------------------------------------------- + +void Hsv::rgbToHsv(VectorArgb const & rgb, Vector & hsv ) +{ + rgbToHsv(rgb.r, rgb.g, rgb.b, hsv.x, hsv.y, hsv.z); +} + +// ---------------------------------------------------------------------- + +void Hsv::rgbToHsv(VectorRgba const & rgb, Vector & hsv ) +{ + rgbToHsv(rgb.r, rgb.g, rgb.b, hsv.x, hsv.y, hsv.z); +} + +//=================================================================== + + diff --git a/engine/shared/library/sharedMath/src/shared/core/Hsv.h b/engine/shared/library/sharedMath/src/shared/core/Hsv.h new file mode 100644 index 00000000..17593a04 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Hsv.h @@ -0,0 +1,33 @@ +//=================================================================== +// +// Hsv.h +// copyright 2005 Sony Online Entertainment +// +//=================================================================== + +#ifndef INCLUDED_Hsv_H +#define INCLUDED_Hsv_H + +//=================================================================== + +class Vector; +class VectorArgb; +class VectorRgba; + +//=================================================================== + +class Hsv +{ + +public: + + static void rgbToHsv(float const red, float const green, float const blue, float &hue, float &saturation, float &value); + + static void rgbToHsv(VectorArgb const & rgb, Vector & hsv ); + static void rgbToHsv(VectorRgba const & rgb, Vector & hsv ); +}; + + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedMath/src/shared/core/Line3d.cpp b/engine/shared/library/sharedMath/src/shared/core/Line3d.cpp new file mode 100644 index 00000000..5b0fefe8 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Line3d.cpp @@ -0,0 +1,9 @@ +// ====================================================================== +// +// Line3d.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +//#include "sharedMath/Line3d.h" diff --git a/engine/shared/library/sharedMath/src/shared/core/Line3d.h b/engine/shared/library/sharedMath/src/shared/core/Line3d.h new file mode 100644 index 00000000..4dc4adea --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Line3d.h @@ -0,0 +1,70 @@ +// ====================================================================== +// +// Line3d.h +// copyright (c) 2001 Sony Online Entertainment +// +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_Line3d_H +#define INCLUDED_Line3d_H + +#include "sharedMath/Vector.h" + +// ---------------------------------------------------------------------- + +class Line3d +{ +public: + + Line3d ( Vector const & p, Vector const & d ); + + Vector const & getPoint ( void ) const; + Vector const & getNormal ( void ) const; + + Vector atParam ( float t ) const; + + void flip ( void ); + Line3d flipped ( void ) const; + +protected: + + Vector m_point; + Vector m_normal; +}; + +// ---------- + +inline Line3d::Line3d ( Vector const & p, Vector const & d ) +: m_point(p), + m_normal(d) +{ +} + +inline Vector const & Line3d::getPoint ( void ) const +{ + return m_point; +} + +inline Vector const & Line3d::getNormal ( void ) const +{ + return m_normal; +} + +inline Vector Line3d::atParam ( float t ) const +{ + return m_point + m_normal * t; +} + +inline void Line3d::flip ( void ) +{ + m_normal = -m_normal; +} + +inline Line3d Line3d::flipped ( void ) const +{ + return Line3d(m_point,-m_normal); +} + +// ---------------------------------------------------------------------- + +#endif // #ifdef INCLUDED_Line3d_H diff --git a/engine/shared/library/sharedMath/src/shared/core/MultiShape.cpp b/engine/shared/library/sharedMath/src/shared/core/MultiShape.cpp new file mode 100644 index 00000000..cb556d62 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/MultiShape.cpp @@ -0,0 +1,414 @@ +// ====================================================================== +// +// MultiShape.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/MultiShape.h" + +#include "sharedMath/Transform.h" +#include "sharedMath/Sphere.h" +#include "sharedMath/Cylinder.h" +#include "sharedMath/OrientedCylinder.h" +#include "sharedMath/AxialBox.h" +#include "sharedMath/YawedBox.h" +#include "sharedMath/OrientedBox.h" + +#include // for max + +MultiShape::ShapeType shapeTable[MultiShape::MSBT_Count][MultiShape::MSOT_Count] = +{ + { MultiShape::MST_Sphere, MultiShape::MST_Sphere, MultiShape::MST_Sphere }, + { MultiShape::MST_Cylinder, MultiShape::MST_Cylinder, MultiShape::MST_OrientedCylinder }, + { MultiShape::MST_AxialBox, MultiShape::MST_YawedBox, MultiShape::MST_OrientedBox } +}; + +// ---------------------------------------------------------------------- + +MultiShape::MultiShape() +: m_baseType ( MSBT_Invalid ), + m_shapeType( MST_Invalid ), + m_center( Vector::zero ), + m_axisX( Vector::unitX ), + m_axisY( Vector::unitY ), + m_axisZ( Vector::unitZ ), + m_extentX( 1.0f ), + m_extentY( 1.0f ), + m_extentZ( 1.0f ) +{ +} + +// ---------- + +MultiShape::MultiShape ( BaseType baseType, + ShapeType shapeType, + Vector const & center, + Vector const & axisX, + Vector const & axisY, + Vector const & axisZ, + float extentX, + float extentY, + float extentZ ) +: m_baseType(baseType), + m_shapeType(shapeType), + m_center(center), + m_axisX(axisX), + m_axisY(axisY), + m_axisZ(axisZ), + m_extentX(extentX), + m_extentY(extentY), + m_extentZ(extentZ) +{ +} + +// ---------- + +MultiShape::MultiShape ( BaseType baseType, + Vector const & center, + Vector const & axisX, + Vector const & axisY, + Vector const & axisZ, + float extentX, + float extentY, + float extentZ ) +: m_baseType(baseType), + m_shapeType(MST_Invalid), + m_center(center), + m_axisX(axisX), + m_axisY(axisY), + m_axisZ(axisZ), + m_extentX(extentX), + m_extentY(extentY), + m_extentZ(extentZ) +{ + updateShapeType(); +} + + +// ---------- + +MultiShape::MultiShape ( Sphere const & shape ) +: m_baseType ( MSBT_Sphere ), + m_shapeType ( MST_Sphere ), + m_center ( shape.getCenter() ), + m_axisX ( shape.getAxisX() ), + m_axisY ( shape.getAxisY() ), + m_axisZ ( shape.getAxisZ() ), + m_extentX ( shape.getExtentX() ), + m_extentY ( shape.getExtentY() ), + m_extentZ ( shape.getExtentZ() ) +{ +} + +// ---------- + +MultiShape::MultiShape ( Cylinder const & shape ) +: m_baseType ( MSBT_Cylinder ), + m_shapeType ( MST_Cylinder ), + m_center ( shape.getCenter() ), + m_axisX ( shape.getAxisX() ), + m_axisY ( shape.getAxisY() ), + m_axisZ ( shape.getAxisZ() ), + m_extentX ( shape.getExtentX() ), + m_extentY ( shape.getExtentY() ), + m_extentZ ( shape.getExtentZ() ) +{ +} + +// ---------- + +MultiShape::MultiShape ( OrientedCylinder const & shape ) +: m_baseType ( MSBT_Cylinder ), + m_shapeType ( MST_OrientedCylinder ), + m_center ( shape.getCenter() ), + m_axisX ( shape.getAxisX() ), + m_axisY ( shape.getAxisY() ), + m_axisZ ( shape.getAxisZ() ), + m_extentX ( shape.getExtentX() ), + m_extentY ( shape.getExtentY() ), + m_extentZ ( shape.getExtentZ() ) +{ +} + +// ---------- + +MultiShape::MultiShape ( AxialBox const & shape ) +: m_baseType ( MSBT_Box ), + m_shapeType ( MST_AxialBox ), + m_center ( shape.getCenter() ), + m_axisX ( shape.getAxisX() ), + m_axisY ( shape.getAxisY() ), + m_axisZ ( shape.getAxisZ() ), + m_extentX ( shape.getExtentX() ), + m_extentY ( shape.getExtentY() ), + m_extentZ ( shape.getExtentZ() ) +{ +} + +// ---------- + +MultiShape::MultiShape ( YawedBox const & shape ) +: m_baseType ( MSBT_Box ), + m_shapeType ( MST_YawedBox ), + m_center ( shape.getCenter() ), + m_axisX ( shape.getAxisX() ), + m_axisY ( shape.getAxisY() ), + m_axisZ ( shape.getAxisZ() ), + m_extentX ( shape.getExtentX() ), + m_extentY ( shape.getExtentY() ), + m_extentZ ( shape.getExtentZ() ) +{ +} + +// ---------- + +MultiShape::MultiShape ( OrientedBox const & shape ) +: m_baseType ( MSBT_Box ), + m_shapeType ( MST_OrientedBox ), + m_center ( shape.getCenter() ), + m_axisX ( shape.getAxisX() ), + m_axisY ( shape.getAxisY() ), + m_axisZ ( shape.getAxisZ() ), + m_extentX ( shape.getExtentX() ), + m_extentY ( shape.getExtentY() ), + m_extentZ ( shape.getExtentZ() ) +{ +} + +// ---------------------------------------------------------------------- + +void MultiShape::updateShapeType ( void ) +{ + const real axisEpsilon = 0.0000001f; + + bool xOK = m_axisX.magnitudeBetweenSquared( Vector::unitX ) < axisEpsilon; + bool yOK = m_axisY.magnitudeBetweenSquared( Vector::unitY ) < axisEpsilon; + bool zOK = m_axisZ.magnitudeBetweenSquared( Vector::unitZ ) < axisEpsilon; + + MultiShape::OrientType orientType = MultiShape::MSOT_Oriented; + + if(xOK && yOK && zOK) orientType = MultiShape::MSOT_AxisAligned; + else if(yOK) orientType = MultiShape::MSOT_Yawed; + + MultiShape::ShapeType shapeType = shapeTable[m_baseType][orientType]; + + m_shapeType = shapeType; +} + +// ---------------------------------------------------------------------- +// @todo - This really needs to go somewhere else. + +// Calculate the radius of the tight-fitting axial cylinder. + +float MultiShape::calcAvoidanceRadius ( void ) const +{ + switch(m_shapeType) + { + case MST_Sphere: + return m_extentX; + case MST_Cylinder: + return m_extentX; + case MST_OrientedCylinder: + { + // Slightly tricky - there are two contact modes between an + // oriented cylinder and its tight-fitting axial cylinder - + // two-contact (cylinder is tilted slightly) and four-contact + // cylinder is on its side). The maximum of those two radii is + // the radius of the tight-fitting cylinder. + + float sinTheta = m_axisY.y; + float cosTheta = sqrt( m_axisY.x * m_axisY.x + m_axisY.z * m_axisY.z ); + + float twoContactRadius = abs(m_extentY * sinTheta + m_extentX * cosTheta); + + float blah = m_extentY * sinTheta; + + float fourContactRadius = sqrt(m_extentX * m_extentX + blah * blah); + + return std::max(twoContactRadius,fourContactRadius); + } + case MST_AxialBox: + return sqrt(m_extentX * m_extentX + m_extentZ * m_extentZ); + case MST_YawedBox: + return sqrt(m_extentX * m_extentX + m_extentZ * m_extentZ); + case MST_OrientedBox: + { + // There's gotta be a cheaper way to calculate this radius... + + // Take four corners at one end of the box, figure out which + // is the farthest from the Y axis. Four is sufficient because + // of symmetry. + + Vector Y = m_axisY * m_extentY; + + Vector A = Y + m_axisX * m_extentX + m_axisZ * m_extentZ; + Vector B = Y + m_axisX * m_extentX - m_axisZ * m_extentZ; + Vector C = Y - m_axisX * m_extentX + m_axisZ * m_extentZ; + Vector D = Y - m_axisX * m_extentX - m_axisZ * m_extentZ; + + float magA = sqrt( A.x * A.x + A.z * A.z ); + float magB = sqrt( B.x * B.x + B.z * B.z ); + float magC = sqrt( C.x * C.x + C.z * C.z ); + float magD = sqrt( D.x * D.x + D.z * D.z ); + + return std::max( std::max(magA,magB), std::max(magC,magD) ); + } + default: + return 0.0f; + } +} + +// ---------------------------------------------------------------------- + +AxialBox MultiShape::getBoundingBox ( void ) const +{ + switch(m_shapeType) + { + case MST_Sphere: + case MST_Cylinder: + case MST_AxialBox: + + return getAxialBox(); + + case MST_YawedBox: + + { + YawedBox box = getYawedBox(); + + AxialBox temp; + + for(int i = 0; i < 8; i++) temp.add(box.getCorner(i)); + + return temp; + } + + case MST_OrientedCylinder: + case MST_OrientedBox: + + { + OrientedBox box = getOrientedBox(); + + AxialBox temp; + + for(int i = 0; i < 8; i++) temp.add(box.getCorner(i)); + + return temp; + } + + default: + DEBUG_WARNING(true,("MultiShape::getBoundingBox - Trying to get a bounding box for an unsupported type")); + return AxialBox(); + } +} + +// ---------- + +Sphere MultiShape::getBoundingSphere ( void ) const +{ + float radius; + if (m_baseType == MSBT_Sphere) + { + radius = m_extentX; + } + else + { + radius = sqrt( m_extentX*m_extentX + m_extentY*m_extentY + m_extentZ*m_extentZ ); + } + + return Sphere( m_center, radius ); +} + +// ---------------------------------------------------------------------- + +Sphere MultiShape::getSphere ( void ) const +{ + return Sphere( m_center, m_extentX ); +} + +// ---------- + +Cylinder MultiShape::getCylinder ( void ) const +{ + return Cylinder( getBase(), m_extentX, getHeight() ); +} + +// ---------- + +OrientedCylinder MultiShape::getOrientedCylinder ( void ) const +{ + return OrientedCylinder( getBase(), m_axisY, m_extentX, getHeight() ); +} + +// ---------- + +AxialBox MultiShape::getAxialBox ( void ) const +{ + Vector min = m_center - Vector( m_extentX, m_extentY, m_extentZ ); + Vector max = m_center + Vector( m_extentX, m_extentY, m_extentZ ); + + return AxialBox( min, max ); +} + +// ---------- + +YawedBox MultiShape::getYawedBox ( void ) const +{ + return YawedBox( getBase(), m_axisX, m_axisZ, m_extentX, m_extentZ, getHeight() ); +} + +// ---------- + +OrientedBox MultiShape::getOrientedBox ( void ) const +{ + return OrientedBox( m_center, m_axisX, m_axisY, m_axisZ, m_extentX, m_extentY, m_extentZ ); +} + +// ---------------------------------------------------------------------- + +Sphere MultiShape::getLocalSphere ( void ) const +{ + return Sphere( Vector::zero, m_extentX ); +} + +// ---------- + +Cylinder MultiShape::getLocalCylinder ( void ) const +{ + return Cylinder( Vector(0.0f,-m_extentY,0.0f), m_extentX, getHeight() ); +} + +// ---------- + +AxialBox MultiShape::getLocalAxialBox ( void ) const +{ + Vector min = -Vector( m_extentX, m_extentY, m_extentZ ); + Vector max = Vector( m_extentX, m_extentY, m_extentZ ); + + return AxialBox( min, max ); +} + +// ---------------------------------------------------------------------- + +Transform MultiShape::getTransform_l2p ( void ) const +{ + Transform temp(Transform::IF_none); + + temp.setLocalFrameIJK_p( m_axisX, m_axisY, m_axisZ ); + temp.setPosition_p( m_center ); + + return temp; +} + +Transform MultiShape::getTransform_p2l ( void ) const +{ + Transform temp(Transform::IF_none); + + temp.invert( getTransform_l2p() ); + + return temp; +} + +// ---------------------------------------------------------------------- + diff --git a/engine/shared/library/sharedMath/src/shared/core/MultiShape.h b/engine/shared/library/sharedMath/src/shared/core/MultiShape.h new file mode 100644 index 00000000..54292f19 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/MultiShape.h @@ -0,0 +1,258 @@ +// ====================================================================== +// +// MultiShape.h +// copyright (c) 2001 Sony Online Entertainment +// +// MultiShape is a simple class that can be used to represent a sphere, +// cylinder, or box, oriented or axial. +// +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_MultiShape_H +#define INCLUDED_MultiShape_H + +#include "sharedMath/Vector.h" + +class Sphere; +class Cylinder; +class OrientedCylinder; +class AxialBox; +class YawedBox; +class OrientedBox; +class Transform; + +// ====================================================================== + +class MultiShape +{ +public: + + enum BaseType + { + MSBT_Sphere, + MSBT_Cylinder, + MSBT_Box, + + MSBT_Count, + MSBT_Invalid, + }; + + enum OrientType + { + MSOT_AxisAligned, + MSOT_Yawed, + MSOT_Oriented, + + MSOT_Count, + MSOT_Invalid, + }; + + enum ShapeType + { + MST_Sphere, + MST_Cylinder, + MST_OrientedCylinder, + MST_AxialBox, + MST_YawedBox, + MST_OrientedBox, + + MST_Count, + MST_Invalid, + }; + + // ---------- + + MultiShape(); + + MultiShape ( BaseType baseType, + Vector const & center, + Vector const & axisX, + Vector const & axisY, + Vector const & axisZ, + float extentX, + float extentY, + float extentZ ); + + MultiShape ( BaseType baseType, + ShapeType shapeType, + Vector const & center, + Vector const & axisX, + Vector const & axisY, + Vector const & axisZ, + float extentX, + float extentY, + float extentZ ); + + explicit MultiShape ( Sphere const & shape ); + explicit MultiShape ( Cylinder const & shape ); + explicit MultiShape ( OrientedCylinder const & shape ); + explicit MultiShape ( AxialBox const & shape ); + explicit MultiShape ( YawedBox const & shape ); + explicit MultiShape ( OrientedBox const & shape ); + + // ---------- + + BaseType getBaseType ( void ) const; + ShapeType getShapeType ( void ) const; + + Vector const & getCenter ( void ) const; + + Vector const & getAxisX ( void ) const; + Vector const & getAxisY ( void ) const; + Vector const & getAxisZ ( void ) const; + + float getExtentX ( void ) const; + float getExtentY ( void ) const; + float getExtentZ ( void ) const; + + void setExtentX ( float newExtent ); + void setExtentY ( float newExtent ); + void setExtentZ ( float newExtent ); + + // ---------- + + Vector getBase ( void ) const; + + float getWidth ( void ) const; + float getHeight ( void ) const; + float getDepth ( void ) const; + + float calcAvoidanceRadius ( void ) const; + void updateShapeType ( void ); + + Sphere getBoundingSphere ( void ) const; + AxialBox getBoundingBox ( void ) const; + + // ---------- + + Sphere getSphere ( void ) const; + Cylinder getCylinder ( void ) const; + OrientedCylinder getOrientedCylinder ( void ) const; + AxialBox getAxialBox ( void ) const; + YawedBox getYawedBox ( void ) const; + OrientedBox getOrientedBox ( void ) const; + + // ---------- + + Sphere getLocalSphere ( void ) const; + Cylinder getLocalCylinder ( void ) const; + AxialBox getLocalAxialBox ( void ) const; + + // ---------- + + Transform getTransform_l2p ( void ) const; + Transform getTransform_p2l ( void ) const; + +protected: + + BaseType m_baseType; + ShapeType m_shapeType; + + Vector m_center; + + Vector m_axisX; + Vector m_axisY; + Vector m_axisZ; + + float m_extentX; + float m_extentY; + float m_extentZ; +}; + +// ---------------------------------------------------------------------- + +inline MultiShape::BaseType MultiShape::getBaseType ( void ) const +{ + return m_baseType; +} + +inline MultiShape::ShapeType MultiShape::getShapeType ( void ) const +{ + return m_shapeType; +} + +// ---------- + +inline Vector const & MultiShape::getCenter ( void ) const +{ + return m_center; +} + +// ---------- + +inline Vector const & MultiShape::getAxisX ( void ) const +{ + return m_axisX; +} + +inline Vector const & MultiShape::getAxisY ( void ) const +{ + return m_axisY; +} + +inline Vector const & MultiShape::getAxisZ ( void ) const +{ + return m_axisZ; +} + +// ---------- + +inline float MultiShape::getExtentX ( void ) const +{ + return m_extentX; +} + +inline float MultiShape::getExtentY ( void ) const +{ + return m_extentY; +} + +inline float MultiShape::getExtentZ ( void ) const +{ + return m_extentZ; +} + +// ---------- + +inline void MultiShape::setExtentX ( float newExtent ) +{ + m_extentX = newExtent; +} + +inline void MultiShape::setExtentY ( float newExtent ) +{ + m_extentY = newExtent; +} + +inline void MultiShape::setExtentZ ( float newExtent ) +{ + m_extentZ = newExtent; +} + +// ---------------------------------------------------------------------- + +inline Vector MultiShape::getBase ( void ) const +{ + return getCenter() - getAxisY() * getExtentY(); +} + +// ---------- + +inline float MultiShape::getWidth ( void ) const +{ + return getExtentX() * 2.0f; +} + +inline float MultiShape::getHeight ( void ) const +{ + return getExtentY() * 2.0f; +} + +inline float MultiShape::getDepth ( void ) const +{ + return getExtentZ() * 2.0f; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedMath/src/shared/core/OrientedBox.cpp b/engine/shared/library/sharedMath/src/shared/core/OrientedBox.cpp new file mode 100644 index 00000000..0c6760c5 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/OrientedBox.cpp @@ -0,0 +1,133 @@ +// ====================================================================== +// +// OrientedBox.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/OrientedBox.h" + +#include "sharedMath/Plane3d.h" +#include "sharedMath/Transform.h" +#include "sharedMath/AxialBox.h" +#include "sharedMath/YawedBox.h" + +// ---------------------------------------------------------------------- + +OrientedBox::OrientedBox ( AxialBox const & s, Transform const & tform ) +: m_center ( tform.rotateTranslate_l2p(s.getCenter()) ), + m_axisX ( tform.rotate_l2p(s.getAxisX()) ), + m_axisY ( tform.rotate_l2p(s.getAxisY()) ), + m_axisZ ( tform.rotate_l2p(s.getAxisZ()) ), + m_extentX ( s.getExtentX() ), + m_extentY ( s.getExtentY() ), + m_extentZ ( s.getExtentZ() ) +{ +} + +// ---------- + +OrientedBox::OrientedBox ( AxialBox const & s ) +: m_center ( s.getCenter() ), + m_axisX ( s.getAxisX() ), + m_axisY ( s.getAxisY() ), + m_axisZ ( s.getAxisZ() ), + m_extentX ( s.getExtentX() ), + m_extentY ( s.getExtentY() ), + m_extentZ ( s.getExtentZ() ) +{ +} + +// ---------- + +OrientedBox::OrientedBox ( YawedBox const & s ) +: m_center ( s.getCenter() ), + m_axisX ( s.getAxisX() ), + m_axisY ( s.getAxisY() ), + m_axisZ ( s.getAxisZ() ), + m_extentX ( s.getExtentX() ), + m_extentY ( s.getExtentY() ), + m_extentZ ( s.getExtentZ() ) +{ +} + +// ---------------------------------------------------------------------- + +Plane3d OrientedBox::getFacePlane ( int whichFace ) const +{ + switch(whichFace) + { + case 0: return Plane3d( m_center + m_axisX * m_extentX, m_axisX ); + case 1: return Plane3d( m_center + m_axisY * m_extentY, m_axisY ); + case 2: return Plane3d( m_center + m_axisZ * m_extentZ, m_axisZ ); + case 3: return Plane3d( m_center - m_axisX * m_extentX, -m_axisX ); + case 4: return Plane3d( m_center - m_axisY * m_extentY, -m_axisY ); + case 5: return Plane3d( m_center - m_axisZ * m_extentZ, -m_axisZ ); + + default: + DEBUG_FATAL(true,("OrientedBox::getFacePlane - invalid face\n")); + return Plane3d(Vector::zero,Vector::zero); + } +} + +// ---------------------------------------------------------------------- + +AxialBox OrientedBox::getLocalShape ( void ) const +{ + return AxialBox( Vector(-m_extentX,-m_extentY,-m_extentZ), + Vector( m_extentX, m_extentY, m_extentZ) ); +} + +Transform OrientedBox::getTransform_l2p ( void ) const +{ + Transform temp; + + temp.setLocalFrameIJK_p( getAxisX(), getAxisY(), getAxisZ() ); + temp.move_p( m_center ); + + return temp; +} + +Transform OrientedBox::getTransform_p2l ( void ) const +{ + Transform temp; + + temp.invert(getTransform_l2p()); + + return temp; +} + +Vector OrientedBox::transformToLocal( Vector const & V ) const +{ + return rotateToLocal( V - m_center ); +} + +Vector OrientedBox::transformToWorld ( Vector const & V ) const +{ + return rotateToWorld(V) + m_center; +} + +Vector OrientedBox::rotateToLocal ( Vector const & V ) const +{ + Vector temp; + + temp.x = V.dot(getAxisX()); + temp.y = V.dot(getAxisY()); + temp.z = V.dot(getAxisZ()); + + return temp; +} + +Vector OrientedBox::rotateToWorld ( Vector const & V ) const +{ + Vector temp = Vector::zero; + + temp += getAxisX() * V.x; + temp += getAxisY() * V.y; + temp += getAxisZ() * V.z; + + return temp; +} + +// ---------------------------------------------------------------------- diff --git a/engine/shared/library/sharedMath/src/shared/core/OrientedBox.h b/engine/shared/library/sharedMath/src/shared/core/OrientedBox.h new file mode 100644 index 00000000..f1dbf6a1 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/OrientedBox.h @@ -0,0 +1,182 @@ +// ====================================================================== +// +// OrientedBox.h +// copyright (c) 2001 Sony Online Entertainment +// +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_OrientedBox_H +#define INCLUDED_OrientedBox_H + +#include "sharedMath/Vector.h" + +class Plane3d; +class AxialBox; +class YawedBox; +class Transform; + +// ====================================================================== + +class OrientedBox +{ +public: + + OrientedBox ( Vector const & center, + Vector const & i, Vector const & j, Vector const & k, + real extentI, real extentJ, real extentK ); + + OrientedBox ( AxialBox const & box, Transform const & tform ); + + explicit OrientedBox ( AxialBox const & box ); + explicit OrientedBox ( YawedBox const & box ); + + // ---------- + + Vector const * getAxes ( void ) const; + float const * getExtents ( void ) const; + + Vector getBase ( void ) const; + Plane3d getFacePlane ( int whichPlane ) const; + + Vector getCorner ( int whichCorner ) const; + + // ---------- + + Vector const & getCenter ( void ) const; + + Vector const & getAxisX ( void ) const; + Vector const & getAxisY ( void ) const; + Vector const & getAxisZ ( void ) const; + + float getExtentX ( void ) const; + float getExtentY ( void ) const; + float getExtentZ ( void ) const; + + // ---------- + + AxialBox getLocalShape ( void ) const; + + Transform getTransform_l2p ( void ) const; + Transform getTransform_p2l ( void ) const; + + Vector transformToLocal ( Vector const & V ) const; + Vector transformToWorld ( Vector const & V ) const; + + Vector rotateToLocal ( Vector const & V ) const; + Vector rotateToWorld ( Vector const & V ) const; + +protected: + + Vector m_center; + + Vector m_axisX; + Vector m_axisY; + Vector m_axisZ; + + float m_extentX; + float m_extentY; + float m_extentZ; +}; + +// ---------------------------------------------------------------------- + +inline OrientedBox::OrientedBox( Vector const & center, + Vector const & axisX, + Vector const & axisY, + Vector const & axisZ, + real extentX, + real extentY, + real extentZ ) +: m_center(center), + m_axisX(axisX), + m_axisY(axisY), + m_axisZ(axisZ), + m_extentX(extentX), + m_extentY(extentY), + m_extentZ(extentZ) +{ +} + +// ---------------------------------------------------------------------- + +inline Vector const * OrientedBox::getAxes ( void ) const +{ + return &m_axisX; +} + +inline float const * OrientedBox::getExtents ( void ) const +{ + return &m_extentX; +} + +inline Vector OrientedBox::getBase ( void ) const +{ + return getCenter() - getAxisY() * getExtentY(); +} + +inline Vector OrientedBox::getCorner ( int whichCorner ) const +{ + Vector X = m_axisX * m_extentX; + Vector Y = m_axisY * m_extentY; + Vector Z = m_axisZ * m_extentZ; + + switch(whichCorner) + { + case 0: return m_center - X - Y - Z; + case 1: return m_center + X - Y - Z; + case 2: return m_center - X - Y + Z; + case 3: return m_center + X - Y + Z; + case 4: return m_center - X + Y - Z; + case 5: return m_center + X + Y - Z; + case 6: return m_center - X + Y + Z; + case 7: return m_center + X + Y + Z; + + default: return Vector(0,0,0); + } +} + +// ---------------------------------------------------------------------- + +inline Vector const & OrientedBox::getCenter ( void ) const +{ + return m_center; +} + +// ---------- + +inline Vector const & OrientedBox::getAxisX ( void ) const +{ + return m_axisX; +} + +inline Vector const & OrientedBox::getAxisY ( void ) const +{ + return m_axisY; +} + +inline Vector const & OrientedBox::getAxisZ ( void ) const +{ + return m_axisZ; +} + +// ---------- + +inline float OrientedBox::getExtentX ( void ) const +{ + return m_extentX; +} + +inline float OrientedBox::getExtentY ( void ) const +{ + return m_extentY; +} + +inline float OrientedBox::getExtentZ ( void ) const +{ + return m_extentZ; +} + +// ---------------------------------------------------------------------- + +#endif + diff --git a/engine/shared/library/sharedMath/src/shared/core/OrientedCircle.cpp b/engine/shared/library/sharedMath/src/shared/core/OrientedCircle.cpp new file mode 100644 index 00000000..55503983 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/OrientedCircle.cpp @@ -0,0 +1,28 @@ +// ====================================================================== +// +// OrientedCircle.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/OrientedCircle.h" + +#include "sharedMath/Circle.h" + +OrientedCircle::OrientedCircle ( Vector const & center, Vector const & axis, float radius ) +: m_center(center), + m_axis(axis), + m_radius(radius) +{ +} + +OrientedCircle::OrientedCircle ( Circle const & circle ) +: m_center( circle.getCenter() ), + m_axis( Vector(0,1,0) ), + m_radius( circle.getRadius() ) +{ +} + + + diff --git a/engine/shared/library/sharedMath/src/shared/core/OrientedCircle.h b/engine/shared/library/sharedMath/src/shared/core/OrientedCircle.h new file mode 100644 index 00000000..aabff743 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/OrientedCircle.h @@ -0,0 +1,57 @@ +// ====================================================================== +// +// OrientedCircle.h +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_OrientedCircle_H +#define INCLUDED_OrientedCircle_H + +#include "sharedMath/Vector.h" + +class Circle; + +// ====================================================================== + +class OrientedCircle +{ +public: + + OrientedCircle ( Vector const & center, Vector const & axis, float radius ); + OrientedCircle ( Circle const & circle ); + + Vector const & getAxis ( void ) const; + float getRadius ( void ) const; + Vector const & getCenter ( void ) const; + +protected: + + Vector m_center; + Vector m_axis; + + float m_radius; +}; + + +// ---------------------------------------------------------------------- + +inline Vector const & OrientedCircle::getAxis ( void ) const +{ + return m_axis; +} + +inline float OrientedCircle::getRadius ( void ) const +{ + return m_radius; +} + +inline Vector const & OrientedCircle::getCenter ( void ) const +{ + return m_center; +} + +// ====================================================================== + +#endif + diff --git a/engine/shared/library/sharedMath/src/shared/core/OrientedCylinder.cpp b/engine/shared/library/sharedMath/src/shared/core/OrientedCylinder.cpp new file mode 100644 index 00000000..8836b644 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/OrientedCylinder.cpp @@ -0,0 +1,121 @@ +// ====================================================================== +// +// OrientedCylinder.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/OrientedCylinder.h" + +#include "sharedMath/Transform.h" +#include "sharedMath/Range.h" +#include "sharedMath/Cylinder.h" +#include "sharedMath/OrientedCircle.h" +#include "sharedMath/Segment3d.h" + + +// ---------------------------------------------------------------------- + +OrientedCylinder::OrientedCylinder ( Cylinder const & s ) +: m_base ( s.getBase() ), + m_axis ( Vector::unitY ), + m_radius ( s.getRadius() ), + m_height ( s.getHeight() ) +{ +} + +OrientedCylinder::OrientedCylinder ( Cylinder const & s, Transform const & tform ) +: m_base ( tform.rotateTranslate_l2p(s.getBase()) ), + m_axis ( tform.rotate_l2p(s.getAxisY()) ), + m_radius ( s.getRadius() ), + m_height ( s.getHeight() ) +{ +} + +// ---------------------------------------------------------------------- + +Segment3d OrientedCylinder::getAxisSegment ( void ) const +{ + return Segment3d( m_base, m_base + m_axis * m_height ); +} + +OrientedCircle OrientedCylinder::getBaseCircle ( void ) const +{ + return OrientedCircle(m_base,m_axis,m_radius); +} + +OrientedCircle OrientedCylinder::getTopCircle ( void ) const +{ + return OrientedCircle(m_base + m_axis * m_height,m_axis,m_radius); +} + +// ---------------------------------------------------------------------- + +Cylinder OrientedCylinder::getLocalShape ( void ) const +{ + float extentY = getExtentY(); + + return Cylinder( Vector(0,-extentY,0), m_radius, extentY * 2.0f ); +} + +Transform OrientedCylinder::getTransform_l2p ( void ) const +{ + Transform temp; + + temp.setLocalFrameIJK_p( getAxisX(), getAxisY(), getAxisZ() ); + temp.move_p( getCenter() ); + + return temp; +} + +Transform OrientedCylinder::getTransform_p2l ( void ) const +{ + Transform temp; + + temp.invert(getTransform_l2p()); + + return temp; +} + +Vector OrientedCylinder::transformToLocal ( Vector const & V ) const +{ + return rotateToLocal(V - getCenter()); +} + +Vector OrientedCylinder::transformToWorld ( Vector const & V ) const +{ + return rotateToWorld(V) + getCenter(); +} + +Vector OrientedCylinder::rotateToLocal ( Vector const & V ) const +{ + Vector temp; + + Vector axisX = getAxisX(); + Vector axisY = getAxisY(); + Vector axisZ = getAxisZ(); + + temp.x = V.dot(axisX); + temp.y = V.dot(axisY); + temp.z = V.dot(axisZ); + + return temp; +} + +Vector OrientedCylinder::rotateToWorld ( Vector const & V ) const +{ + Vector temp = Vector::zero; + + Vector axisX = getAxisX(); + Vector axisY = getAxisY(); + Vector axisZ = getAxisZ(); + + temp += axisX * V.x; + temp += axisY * V.y; + temp += axisZ * V.z; + + return temp; +} + +// ---------------------------------------------------------------------- diff --git a/engine/shared/library/sharedMath/src/shared/core/OrientedCylinder.h b/engine/shared/library/sharedMath/src/shared/core/OrientedCylinder.h new file mode 100644 index 00000000..532b2e63 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/OrientedCylinder.h @@ -0,0 +1,175 @@ +// ====================================================================== +// +// OrientedCylinder.h +// copyright (c) 2001 Sony Online Entertainment +// +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_OrientedCylinder_H +#define INCLUDED_OrientedCylinder_H + + +#include "sharedMath/Vector.h" + +class Transform; +class Range; +class Cylinder; +class OrientedCircle; +class Segment3d; + +// ====================================================================== + +class OrientedCylinder +{ +public: + + OrientedCylinder(); + OrientedCylinder ( Vector const & base, Vector const & axis, float radius, float height ); + + explicit OrientedCylinder ( Cylinder const & cyl ); + OrientedCylinder( Cylinder const & s, Transform const & tform ); + + // ---------- + + Vector const & getBase ( void ) const; + Vector const & getAxis ( void ) const; + + float getRadius ( void ) const; + float getHeight ( void ) const; + + // ---------- + // Sub-shapes + + Segment3d getAxisSegment ( void ) const; + OrientedCircle getBaseCircle ( void ) const; + OrientedCircle getTopCircle ( void ) const; + + // ---------- + + Vector getCenter ( void ) const; + + Vector getAxisX ( void ) const; + Vector getAxisY ( void ) const; + Vector getAxisZ ( void ) const; + + float getExtentX ( void ) const; + float getExtentY ( void ) const; + float getExtentZ ( void ) const; + + // ---------- + + Transform getTransform_l2p ( void ) const; + Transform getTransform_p2l ( void ) const; + + Vector transformToLocal ( Vector const & V ) const; + Vector transformToWorld ( Vector const & V ) const; + + Vector rotateToLocal ( Vector const & V ) const; + Vector rotateToWorld ( Vector const & V ) const; + + Cylinder getLocalShape ( void ) const; + +protected: + + Vector m_base; + Vector m_axis; + + float m_radius; + float m_height; +}; + +// ---------------------------------------------------------------------- + +inline OrientedCylinder::OrientedCylinder () +: m_base( Vector::zero ), + m_axis( Vector(0.0f,1.0f,0.0f) ), + m_radius( 1.0f ), + m_height( 1.0f ) +{ +} + +inline OrientedCylinder::OrientedCylinder ( Vector const & base, Vector const & axis, float radius, float height ) +: m_base( base ), + m_axis( axis ), + m_radius( radius ), + m_height( height ) +{ + IGNORE_RETURN(m_axis.normalize()); +} + +// ---------- + +inline Vector const & OrientedCylinder::getBase ( void ) const +{ + return m_base; +} + +inline Vector const & OrientedCylinder::getAxis ( void ) const +{ + return m_axis; +} + +inline float OrientedCylinder::getRadius ( void ) const +{ + return m_radius; +} + +inline float OrientedCylinder::getHeight ( void ) const +{ + return m_height; +} + +// ---------------------------------------------------------------------- + +inline Vector OrientedCylinder::getCenter ( void ) const +{ + return m_base + m_axis * (m_height / 2.0f); +} + +inline Vector OrientedCylinder::getAxisX ( void ) const +{ + Vector projected(-m_axis.z,0.0f,m_axis.x); + + if(projected.normalize()) + { + return projected; + } + else + { + return Vector::unitX; + } +} + +inline Vector OrientedCylinder::getAxisY ( void ) const +{ + return m_axis; +} + +inline Vector OrientedCylinder::getAxisZ ( void ) const +{ + Vector temp = getAxisX().cross(m_axis); + + temp.normalize(); + + return temp; +} + +inline float OrientedCylinder::getExtentX ( void ) const +{ + return m_radius; +} + +inline float OrientedCylinder::getExtentY ( void ) const +{ + return m_height / 2.0f; +} + +inline float OrientedCylinder::getExtentZ ( void ) const +{ + return m_radius; +} + +// ====================================================================== + +#endif + diff --git a/engine/shared/library/sharedMath/src/shared/core/Plane3d.cpp b/engine/shared/library/sharedMath/src/shared/core/Plane3d.cpp new file mode 100644 index 00000000..14d54f47 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Plane3d.cpp @@ -0,0 +1,17 @@ +// ====================================================================== +// +// Plane3d.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/Plane3d.h" + +#include "sharedMath/Plane.h" + +Plane3d::Plane3d ( Plane const & plane ) +: m_point( plane.getNormal() * -plane.getD() ), + m_normal( plane.getNormal() ) +{ +} diff --git a/engine/shared/library/sharedMath/src/shared/core/Plane3d.h b/engine/shared/library/sharedMath/src/shared/core/Plane3d.h new file mode 100644 index 00000000..ccc599b1 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Plane3d.h @@ -0,0 +1,91 @@ +// ====================================================================== +// +// Plane3d.h +// copyright (c) 2001 Sony Online Entertainment +// +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_Plane3d_H +#define INCLUDED_Plane3d_H + +#include "sharedMath/Vector.h" + +class Plane; + +// ---------------------------------------------------------------------- + +class Plane3d +{ +public: + + Plane3d(); + + Plane3d ( Plane const & plane ); + Plane3d ( Vector const & p, Vector const & n ); + Plane3d ( Vector const & A, Vector const & B, Vector const & C ); + + // build a plane but don't worry about normalizing the m_normal + + static Plane3d NoNorm( Vector const & p, Vector const & n ); + + Vector const & getPoint ( void ) const; + Vector const & getNormal ( void ) const; + + bool isNormalized ( void ) const; //@return True if the plane's normal is unit-length + +protected: + + Vector m_point; + Vector m_normal; +}; + +// ---------- + +inline Plane3d::Plane3d() +{ +} + +inline Plane3d::Plane3d ( Vector const & p, Vector const & n ) +: m_point(p), m_normal(n) +{ + IGNORE_RETURN( m_normal.normalize() ); +} + +inline Plane3d::Plane3d ( Vector const & A, Vector const & B, Vector const & C ) +: m_point(A), m_normal( (B-A).cross(C-A) ) +{ + IGNORE_RETURN( m_normal.normalize() ); +} + +// build a plane but don't worry about normalizing the m_normal + +inline Plane3d Plane3d::NoNorm( Vector const & p, Vector const & n ) +{ + Plane3d temp; + + temp.m_point = p; + temp.m_normal = n; + + return temp; +} + +inline Vector const & Plane3d::getPoint ( void ) const +{ + return m_point; +} + +inline Vector const & Plane3d::getNormal ( void ) const +{ + return m_normal; +} + +inline bool Plane3d::isNormalized ( void ) const +{ +// return m_normal.isNormalized() + return true; +} + +// ---------------------------------------------------------------------- + +#endif // #ifdef INCLUDED_Plane3d_H + diff --git a/engine/shared/library/sharedMath/src/shared/core/Quadratic.cpp b/engine/shared/library/sharedMath/src/shared/core/Quadratic.cpp new file mode 100644 index 00000000..d4722571 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Quadratic.cpp @@ -0,0 +1,68 @@ +// ====================================================================== +// +// Quadratic.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/Quadratic.h" + + +bool Quadratic::solveFor ( float value, float & out1, float & out2 ) const +{ + if((m_A == 0.0f) && (m_B == 0.0f)) + { + if(m_C == value) + { + out1 = -REAL_MAX; + out2 = REAL_MAX; + + return true; + } + else + { + return false; + } + } + + // ---------- + + if(m_A == 0.0f) + { + out1 = (value - m_C) / m_B; + out2 = (value - m_C) / m_B; + + return true; + } + + // ---------- + + float a = m_A; + float b = m_B; + float c = m_C - value; + + float det = b*b - 4*a*c; + + if(det < 0) return false; + + float s = sqrt(det); + + float i = 1.0f / (2.0f * a); + + float o1 = (-b + s) * i; + float o2 = (-b - s) * i; + + if(o1 < o2) + { + out1 = o1; + out2 = o2; + } + else + { + out1 = o2; + out2 = o1; + } + + return true; +} diff --git a/engine/shared/library/sharedMath/src/shared/core/Quadratic.h b/engine/shared/library/sharedMath/src/shared/core/Quadratic.h new file mode 100644 index 00000000..8aa15cfd --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Quadratic.h @@ -0,0 +1,42 @@ +// ====================================================================== +// +// Quadratic.h +// copyright (c) 2001 Sony Online Entertainment +// +// Simple class to represent a quadratic equation +// +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_Quadratic_H +#define INCLUDED_Quadratic_H + +// ====================================================================== + +class Quadratic +{ +public: + + Quadratic ( float a, float b, float c ); + + // ---------- + + bool solveFor( float value, float & out1, float & out2 ) const; + + // ---------- + + float m_A; + float m_B; + float m_C; +}; + +// ---------------------------------------------------------------------- + +inline Quadratic::Quadratic ( float a, float b, float c ) +: m_A(a), m_B(b), m_C(c) +{ +} + +// ---------------------------------------------------------------------- + +#endif + diff --git a/engine/shared/library/sharedMath/src/shared/core/Range.cpp b/engine/shared/library/sharedMath/src/shared/core/Range.cpp new file mode 100644 index 00000000..c48163e7 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Range.cpp @@ -0,0 +1,71 @@ +// ====================================================================== +// +// Range.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/Range.h" +#include "sharedRandom/Random.h" + +#include + +Range Range::empty ( REAL_MAX, -REAL_MAX ); +Range Range::inf ( -REAL_MAX, REAL_MAX ); +Range Range::plusInf ( 0.0f, REAL_MAX ); +Range Range::negInf (-REAL_MAX,0.0f); +Range Range::unit (0.0f,1.0f); + +Range Range::enclose ( Range const & A, float V ) +{ + if(A.isEmpty()) + { + return Range(V,V); + } + else + { + return Range(std::min(A.getMin(),V),std::max(A.getMax(),V)); + } +} + +Range Range::enclose ( Range const & A, Range const & B ) +{ + if(A.isEmpty()) + { + if(B.isEmpty()) + { + return Range::empty; + } + else + { + return B; + } + } + else + { + if(B.isEmpty()) + { + return A; + } + else + { + return Range(std::min(A.getMin(),B.getMin()), std::max(A.getMax(),B.getMax())); + } + } +} + +Range Range::enclose ( Range const & A, Range const & B, Range const & C ) +{ + return enclose(enclose(A,B),C); +} + +Range Range::enclose ( Range const & A, Range const & B, Range const & C, Range const & D ) +{ + return enclose(enclose(A,B),enclose(C,D)); +} + +float Range::random() const +{ + return (m_min > m_max) ? Random::randomReal(m_max, m_min) : Random::randomReal(m_min, m_max); +} diff --git a/engine/shared/library/sharedMath/src/shared/core/Range.h b/engine/shared/library/sharedMath/src/shared/core/Range.h new file mode 100644 index 00000000..790e3378 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Range.h @@ -0,0 +1,225 @@ +// ====================================================================== +// +// Range.h +// copyright (c) 2001 Sony Online Entertainment +// +// Simple class to represent a 1D range (essentially a 1d bounding box) +// +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_Range_H +#define INCLUDED_Range_H + +#include "sharedFoundation/Misc.h" + +// ====================================================================== + +class Range +{ +public: + + Range(); + Range( float newMin, float newMax ); + + // ---------- + + float const & getMin ( void ) const; + float const & getMax ( void ) const; + + void setMin ( float const & newMin ); + void setMax ( float const & newMax ); + void set(float const newMin, float const newMax ); + + // ---------- + + bool isBelow ( Range const & R ) const; + bool isAbove ( Range const & R ) const; + bool isTouchingBelow ( Range const & R ) const; + bool isTouchingAbove ( Range const & R ) const; + bool isEmpty ( void ) const; + + // ---------- + + bool contains ( float V ) const; + + Range operator + ( float offset ) const; + + bool operator < ( Range const & R ) const; + bool operator == ( Range const & R ) const; + bool operator != ( Range const & R ) const; + + float clamp ( float V ) const; + + float linearInterpolate(float t) const; + float cubicInterpolate(float t) const; + float random() const; + + // ---------- + + static Range empty; + static Range inf; // (-inf,inf) + + static Range plusInf; // (0,inf) + static Range negInf; // (-inf,0) + static Range unit; // (0,1) + + // ---------- + + static Range enclose ( Range const & A, float V ); + static Range enclose ( Range const & A, Range const & B ); + static Range enclose ( Range const & A, Range const & B, Range const & C ); + static Range enclose ( Range const & A, Range const & B, Range const & C, Range const & D ); + +protected: + + float m_min; + float m_max; +}; + +// ---------------------------------------------------------------------- + +inline Range::Range() : m_min(REAL_MAX), m_max(-REAL_MAX) +{ +} + +inline Range::Range ( float newMin, float newMax ) : m_min(newMin), m_max(newMax) +{ +} + +// ---------- + +inline float const & Range::getMin ( void ) const +{ + return m_min; +} + +inline float const & Range::getMax ( void ) const +{ + return m_max; +} + +inline void Range::setMin ( float const & newMin ) +{ + m_min = newMin; +} + +inline void Range::setMax ( float const & newMax ) +{ + m_max = newMax; +} + +inline void Range::set(float const newMin, float const newMax ) +{ + setMin(newMin); + setMax(newMax); +} + + +// ---------- + +inline bool Range::isBelow ( Range const & R ) const +{ + return m_max < R.m_min; +} + +inline bool Range::isAbove ( Range const & R ) const +{ + return m_min > R.m_max; +} + +inline bool Range::isTouchingBelow ( Range const & R ) const +{ + return m_max == R.m_min; +} + +inline bool Range::isTouchingAbove ( Range const & R ) const +{ + return m_min == R.m_max; +} + +inline bool Range::isEmpty ( void ) const +{ + return m_max < m_min; +} + +// ---------- + +inline bool Range::contains ( float V ) const +{ + if(V < m_min) return false; + if(V > m_max) return false; + + return true; +} + +// ---------- + +inline Range Range::operator + ( float offset ) const +{ + return Range(m_min + offset, m_max + offset); +} + +inline bool Range::operator < ( Range const & R ) const +{ + if( m_min < R.m_min ) + { + return true; + } + else if( m_min == R.m_min ) + { + return m_max < R.m_max; + } + else + { + return false; + } +} + +inline bool Range::operator == ( Range const & R ) const +{ + if(m_min != R.m_min) return false; + if(m_max != R.m_max) return false; + + return true; +} + +inline bool Range::operator != ( Range const & R ) const +{ + if(m_min != R.m_min) return true; + if(m_max != R.m_max) return true; + + return false; +} + +// ---------- + +inline float Range::clamp ( float V ) const +{ + if(isEmpty()) + { + return V; + } + else + { + return ::clamp(m_min, V, m_max); + } +} + +// ---------- + +inline float Range::linearInterpolate(float const t) const +{ + return ::linearInterpolate(m_min, m_max, t); +} + +// ---------- + +inline float Range::cubicInterpolate(float const t) const +{ + return ::cubicInterpolate(m_min, m_max, t); +} + +// ------------------------------------------------::---------------------- + +#endif + diff --git a/engine/shared/library/sharedMath/src/shared/core/RangeLoop.cpp b/engine/shared/library/sharedMath/src/shared/core/RangeLoop.cpp new file mode 100644 index 00000000..1fab4723 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/RangeLoop.cpp @@ -0,0 +1,458 @@ +// ====================================================================== +// +// RangeLoop.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/RangeLoop.h" + +#include "sharedFoundation/ConfigFile.h" +#include "sharedMath/ConfigSharedMath.h" + +// ---------- + +float RangeLoop::clip ( float x ) +{ + return x - (float)floor(x); +} + +// distance you have to go in the positive direction to get from A to B + +float RangeLoop::distancePositive ( float A, float B ) +{ + A = clip(A); + B = clip(B); + + return (B > A) ? -A + B : 1 - A + B; +} + +// distance you have to go in the negative direction to get from A to B + +float RangeLoop::distanceNegative ( float A, float B ) +{ + A = clip(A); + B = clip(B); + + return (B > A) ? 1 + A - B : A - B; +} + +bool RangeLoop::containsInclusive ( float min, float max, float x ) +{ + min = clip(min); + max = clip(max); + x = clip(x); + + if(max > min) + { + return ( x >= min ) && ( x <= max ); + } + else + { + return ( x >= min ) || ( x <= max ); + } +} + +// distancePositive(A,B) + distanceNegative(A,B) == 1.0 + +// signed distance from A to B via whichever way's closer + +float distance ( float A, float B ) +{ + A = RangeLoop::clip(A); + B = RangeLoop::clip(B); + + float positive = RangeLoop::distancePositive(A,B); + + if(positive <= 0.5) + { + return positive; + } + else + { + return positive-1; + } +} + + + +// ====================================================================== + +RangeLoop::RangeLoop ( void ) +: m_min( -1.0f ), + m_max( -1.0f ) +{ +} + +RangeLoop::RangeLoop ( float min, float max ) +: m_min( clip(min) ), + m_max( clip(max) ) +{ + if(abs(max-min) >= 1.0f) + { + m_min = 0.0f; + m_max = 1.0f; + } +} + +// ---------- + +RangeLoop RangeLoop::empty; +RangeLoop RangeLoop::full(0.0f,1.0f); + +// ---------------------------------------------------------------------- + +bool RangeLoop::isEmpty ( void ) const +{ + return (m_min == -1.0f) && (m_max == -1.0f); +} + +bool RangeLoop::isFull ( void ) const +{ + return (m_min == 0.0f) && (m_max == 1.0f); +} + +float RangeLoop::atParam ( float t ) const +{ + if(m_min <= m_max) + { + return m_min + (m_max - m_min) * t; + } + else + { + return clip( m_min + (m_max - m_min + 1.0f) * t ); + } +} + +float RangeLoop::getSize ( void ) const +{ + if(m_min <= m_max) + { + return m_max - m_min; + } + else + { + return m_max - m_min + 1.0f; + } +} + +// ---------------------------------------------------------------------- +// true if +// [----R----] +// xxxxxxxxxxx + +bool RangeLoop::containsInclusive ( float x ) const +{ + if(isFull()) return true; + if(isEmpty()) return false; + + x = clip(x); + + if(m_max == m_min) + { + return x == m_min; + } + else if(m_max > m_min) + { + return ( x >= m_min ) && ( x <= m_max ); + } + else + { + return ( x >= m_min ) || ( x <= m_max ); + } +} + +// ---------- +// true if +// (----R----) +// xxxxxxxxx + +bool RangeLoop::containsExclusive ( float x ) const +{ + if(isFull()) return true; + if(isEmpty()) return false; + + x = clip(x); + + if(m_max == m_min) + { + return x == m_min; + } + else if(m_max > m_min) + { + return ( x > m_min ) && ( x < m_max ); + } + else + { + return ( x > m_min ) || ( x < m_max ); + } +} + +// ---------- +// true if +// (----A----) +// (----B----) + +bool RangeLoop::overlapPositive ( RangeLoop const & R ) const +{ + if(isEmpty() || R.isEmpty()) return false; + if(isFull() || R.isFull()) return true; + + if(!containsExclusive(R.m_min)) return false; + if( containsExclusive(R.m_max)) return false; + + if(!R.containsExclusive(m_max)) return false; + if( R.containsExclusive(m_min)) return false; + + return true; +} + +// true if +// (----B----) +// (----A----) + +bool RangeLoop::overlapNegative ( RangeLoop const & R ) const +{ + if(isEmpty() || R.isEmpty()) return false; + if(isFull() || R.isFull()) return true; + + if(!containsExclusive(R.m_max)) return false; + if( containsExclusive(R.m_min)) return false; + + if(!R.containsExclusive(m_min)) return false; + if( R.containsExclusive(m_max)) return false; + + return true; +} + +// true if +// [--A--] +// [--B--] + +bool RangeLoop::disjointInclusive ( RangeLoop const & R ) const +{ + if(isEmpty() || R.isEmpty()) return false; + if(isFull() || R.isFull()) return true; + + if(containsInclusive(R.m_min)) return false; + if(containsInclusive(R.m_max)) return false; + + if(R.containsInclusive(m_min)) return false; + if(R.containsInclusive(m_max)) return false; + + return true; +} + +// true if +// (--A--) +// (--B--) + +bool RangeLoop::disjointExclusive ( RangeLoop const & R ) const +{ + if(isEmpty() || R.isEmpty()) return true; + if(isFull() || R.isFull()) return false; + + if(containsExclusive(R.m_min)) return false; + if(containsExclusive(R.m_max)) return false; + + if(R.containsExclusive(m_min)) return false; + if(R.containsExclusive(m_max)) return false; + + return true; +} + +bool RangeLoop::contains ( RangeLoop const & R ) const +{ + if(isEmpty() || R.isEmpty()) return false; + if(isFull()) return true; + if(R.isFull()) return false; + + if(!containsInclusive(R.m_min)) return false; + if(!containsInclusive(R.m_max)) return false; + + return true; +} + +bool RangeLoop::operator == ( RangeLoop const & R ) const +{ + if(m_min != R.m_min) return false; + if(m_max != R.m_max) return false; + + return true; +} + +// ---------- + +RangeLoop RangeLoop::enclose ( float A, float B ) +{ + if(distancePositive(A,B) < 0.5f) + { + return RangeLoop(A,B); + } + else + { + return RangeLoop(B,A); + } +} + +RangeLoop RangeLoop::enclose ( RangeLoop const & A, float B ) +{ + if(A.isEmpty()) + { + return RangeLoop(B,B); + } + else if(A.isFull()) + { + return RangeLoop::full; + } + else if(A.containsInclusive(B)) + { + return A; + } + else + { + float distA = distancePositive(A.getMax(),B); + float distB = distanceNegative(A.getMin(),B); + + if(distA < distB) + { + return RangeLoop(A.getMin(),B); + } + else + { + return RangeLoop(B,A.getMax()); + } + } +} + +RangeLoop RangeLoop::enclose ( RangeLoop const & A, RangeLoop const & B ) +{ +#ifdef _DEBUG + + A.validate(); + B.validate(); + +#endif + + // ---------- + // check full ranges + + bool fullA = A.isFull(); + bool fullB = B.isFull(); + + if(fullA || fullB) + { + return RangeLoop::full; + } + + // ---------- + // check empty ranges + + bool emptyA = A.isEmpty(); + bool emptyB = B.isEmpty(); + + if(emptyA && emptyB) + { + return RangeLoop::empty; + } + else if(emptyA) + { + return B; + } + else if(emptyB) + { + return A; + } + + // ---------- + // check containing/disjoint ranges + + if(A.contains(B)) + { + return A; + } + else if(B.contains(A)) + { + return B; + } + else if (A.disjointExclusive(B)) + { + float distA = distancePositive(A.getMin(),B.getMax()); + float distB = distanceNegative(A.getMax(),B.getMin()); + + if(distA < distB) + { + return RangeLoop(A.getMin(),B.getMax()); + } + else + { + return RangeLoop(B.getMin(),A.getMax()); + } + } + + // ---------- + // check overlapping ranges + + bool overlapAB = A.overlapPositive(B); + bool overlapBA = B.overlapPositive(A); + + if(overlapAB && overlapBA) + { + return RangeLoop(0.0f,1.0f); + } + else if(overlapAB) + { + return RangeLoop(A.getMin(),B.getMax()); + } + else if(overlapBA) + { + return RangeLoop(B.getMin(),A.getMax()); + } + + // ---------- + // check adjacent ranges + + bool touchAB = (A.getMax() == B.getMin()); + bool touchBA = (B.getMax() == A.getMin()); + + if(touchAB && touchBA) + { + return RangeLoop(0.0f,1.0f); + } + else if(touchAB) + { + return RangeLoop(A.getMin(),B.getMax()); + } + else if(touchBA) + { + return RangeLoop(B.getMin(),A.getMax()); + } + + // ---------- + // something's screwed up - we should have caught all the cases by now + + WARNING_STRICT_FATAL(ConfigSharedMath::getReportRangeLoopWarnings(),("RangeLoop::enclose is broken - (%f,%f) (%f,%f)\n",A.getMin(),A.getMax(),B.getMin(),B.getMax())); + return RangeLoop(0.0f,1.0f); +} + +// ---------------------------------------------------------------------- + +void RangeLoop::validate ( void ) const +{ +#ifdef _DEBUG + + if(isFull()) return; + + if(isEmpty()) return; + + if((m_min < 0.0f) || (m_max >= 1.0f)) + { + DEBUG_WARNING(ConfigSharedMath::getReportRangeLoopWarnings(),("RangeLoop::validate - range (%f,%f) is invalid\n",m_min,m_max)); + } + +#endif +} + + +// ====================================================================== diff --git a/engine/shared/library/sharedMath/src/shared/core/RangeLoop.h b/engine/shared/library/sharedMath/src/shared/core/RangeLoop.h new file mode 100644 index 00000000..d31478c4 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/RangeLoop.h @@ -0,0 +1,120 @@ +// ====================================================================== +// +// RangeLoop.h +// copyright (c) 2001 Sony Online Entertainment +// +// This class requires a bit of explanation - it represents a 1d range +// of numbers defined over the numerical ring [0,1). Because the ring +// is closed, certain operations aren't well-defined - there's no +// way to express the notions of "greater than" or "less than" nor is +// there a unique way to express the distance between two values. + +// Nevertheless, this class is very useful for representing ranges of +// things that are logically loops, like angles and such. + +// Definitions - + +// [ 0 ,0.2 ] - all numbers between 0 and 0.2, inclusive + +// [ 0.4, 0.2 ] - the union of [ 0.4, 1 ) and [ 0, 0.2 ] + + +// This class really ought to be called RingRange + + +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_RangeLoop_H +#define INCLUDED_RangeLoop_H + +// ====================================================================== + +class RangeLoop +{ +public: + + RangeLoop(); + RangeLoop( float newMin, float newMax ); + + static RangeLoop empty; + static RangeLoop full; + + // ---------- + + bool isEmpty ( void ) const; + bool isFull ( void ) const; + + float getMin ( void ) const; + float getMax ( void ) const; + + void setMin ( float newMin ); + void setMax ( float newMax ); + + float atParam ( float t ) const; + + float getSize ( void ) const; + + + // ---------- + + bool overlapPositive ( RangeLoop const & R ) const; // exclusive test + bool overlapNegative ( RangeLoop const & R ) const; // exclusive test + + bool disjointInclusive ( RangeLoop const & R ) const; + bool disjointExclusive ( RangeLoop const & R ) const; + + bool containsInclusive ( float V ) const; + bool containsExclusive ( float V ) const; + + bool contains ( RangeLoop const & R ) const; + + bool operator == ( RangeLoop const & R ) const; + bool operator != ( RangeLoop const & R ) const; + + // ---------- + // accessory functions + + static float clip ( float V ); + static float distancePositive ( float A, float B ); + static float distanceNegative ( float A, float B ); + + static bool containsInclusive ( float min, float max, float V ); + + static RangeLoop enclose ( float A, float B); + static RangeLoop enclose ( RangeLoop const & A, float B); + static RangeLoop enclose ( RangeLoop const & A, RangeLoop const & B); + +protected: + + void validate ( void ) const; + + float m_min; + float m_max; +}; + +// ---------------------------------------------------------------------- + +inline float RangeLoop::getMin ( void ) const +{ + return m_min; +} + +inline float RangeLoop::getMax ( void ) const +{ + return m_max; +} + +inline void RangeLoop::setMin ( float min ) +{ + m_min = clip(min); +} + +inline void RangeLoop::setMax ( float max ) +{ + m_max = clip(max); +} + +// ====================================================================== + +#endif + diff --git a/engine/shared/library/sharedMath/src/shared/core/Ray3d.cpp b/engine/shared/library/sharedMath/src/shared/core/Ray3d.cpp new file mode 100644 index 00000000..baa28493 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Ray3d.cpp @@ -0,0 +1,18 @@ +// ====================================================================== +// +// Ray3d.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/Ray3d.h" + +#include "sharedMath/Line3d.h" + +Line3d Ray3d::getLine ( void ) const +{ + return Line3d(m_point,m_normal); +} + + diff --git a/engine/shared/library/sharedMath/src/shared/core/Ray3d.h b/engine/shared/library/sharedMath/src/shared/core/Ray3d.h new file mode 100644 index 00000000..0a84b174 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Ray3d.h @@ -0,0 +1,61 @@ +// ====================================================================== +// +// Ray3d.h +// copyright (c) 2001 Sony Online Entertainment +// +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_Ray3d_H +#define INCLUDED_Ray3d_H + +#include "sharedMath/Vector.h" + +class Line3d; + +// ---------------------------------------------------------------------- + +class Ray3d +{ +public: + + Ray3d ( Vector const & p, Vector const & d ); + + Vector const & getPoint ( void ) const; + Vector const & getNormal ( void ) const; + + Line3d getLine ( void ) const; + + Vector atParam ( float t ) const; + +protected: + + Vector m_point; + Vector m_normal; +}; + +// ---------- + +inline Ray3d::Ray3d ( Vector const & p, Vector const & d ) +: m_point(p), m_normal(d) +{ +} + +inline Vector const & Ray3d::getPoint ( void ) const +{ + return m_point; +} + +inline Vector const & Ray3d::getNormal ( void ) const +{ + return m_normal; +} + +inline Vector Ray3d::atParam ( float t ) const +{ + return m_point + m_normal * t; +} + +// ---------------------------------------------------------------------- + +#endif // #ifdef INCLUDED_Ray3d_H + diff --git a/engine/shared/library/sharedMath/src/shared/core/Ribbon3d.cpp b/engine/shared/library/sharedMath/src/shared/core/Ribbon3d.cpp new file mode 100644 index 00000000..5df74da9 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Ribbon3d.cpp @@ -0,0 +1,56 @@ +// ====================================================================== +// +// Ribbon3d.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/Ribbon3d.h" + +#include "sharedMath/Segment3d.h" +#include "sharedMath/Line3d.h" +#include "sharedMath/Plane3d.h" + + +Ribbon3d::Ribbon3d ( Vector const & pointA, Vector const & pointB, Vector const & dir ) +: m_pointA( pointA ), + m_pointB( pointB ), + m_dir( dir ) +{ +} + +Ribbon3d::Ribbon3d ( Segment3d const & seg, Vector const & dir ) +: m_pointA( seg.getBegin() ), + m_pointB( seg.getEnd() ), + m_dir( dir ) +{ +} + +Ribbon3d::Ribbon3d ( Line3d const & line, Vector const & delta ) +: m_pointA( line.getPoint() ), + m_pointB( line.getPoint() + delta ), + m_dir( line.getNormal() ) +{ +} + +// ---------- + +Plane3d Ribbon3d::getPlane( void ) const +{ + Vector E = m_pointB - m_pointA; + Vector N = E.cross( m_dir ); + + return Plane3d( m_pointA, N ); +} + +Line3d Ribbon3d::getEdgeA( void ) const +{ + return Line3d( m_pointA, m_dir ); +} + +Line3d Ribbon3d::getEdgeB( void ) const +{ + return Line3d( m_pointB, m_dir ); +} + diff --git a/engine/shared/library/sharedMath/src/shared/core/Ribbon3d.h b/engine/shared/library/sharedMath/src/shared/core/Ribbon3d.h new file mode 100644 index 00000000..251c30e2 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Ribbon3d.h @@ -0,0 +1,72 @@ +// ====================================================================== +// +// Ribbon3d.h +// copyright (c) 2001 Sony Online Entertainment +// +// A ribbon is a segment swept along a line. +// +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_Ribbon3d_H +#define INCLUDED_Ribbon3d_H + +#include "sharedMath/Vector.h" + +class Segment3d; +class Line3d; +class Plane3d; + +// ---------------------------------------------------------------------- + +class Ribbon3d +{ +public: + + Ribbon3d ( Vector const & pointA, Vector const & pointB, Vector const & dir ); + + Ribbon3d ( Segment3d const & seg, Vector const & dir ); + Ribbon3d ( Line3d const & line, Vector const & delta ); + + Vector const & getPointA ( void ) const; + Vector const & getPointB ( void ) const; + Vector const & getDir ( void ) const; + Vector getDelta ( void ) const; + + Plane3d getPlane ( void ) const; + + Line3d getEdgeA ( void ) const; + Line3d getEdgeB ( void ) const; + +protected: + + Vector m_pointA; + Vector m_pointB; + Vector m_dir; +}; + +// ---------------------------------------------------------------------- + +inline Vector const & Ribbon3d::getPointA ( void ) const +{ + return m_pointA; +} + +inline Vector const & Ribbon3d::getPointB ( void ) const +{ + return m_pointB; +} + +inline Vector const & Ribbon3d::getDir ( void ) const +{ + return m_dir; +} + +inline Vector Ribbon3d::getDelta ( void ) const +{ + return m_pointB - m_pointA; +} + +// ---------------------------------------------------------------------- + +#endif // #ifndef INCLUDED_Ribbon3d_H + diff --git a/engine/shared/library/sharedMath/src/shared/core/Ring.cpp b/engine/shared/library/sharedMath/src/shared/core/Ring.cpp new file mode 100644 index 00000000..a04d7b97 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Ring.cpp @@ -0,0 +1,35 @@ +// ====================================================================== +// +// Ring.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/Ring.h" + +#include "sharedMath/Range.h" +#include "sharedMath/Plane3d.h" + +Range Ring::getRangeX ( void ) const +{ + return Range( m_center.x - m_radius, m_center.x + m_radius ); +} + +Range Ring::getRangeZ ( void ) const +{ + return Range( m_center.z - m_radius, m_center.z + m_radius ); +} + +Range Ring::getLocalRangeX ( void ) const +{ + return Range( -m_radius, m_radius ); +} + +Plane3d Ring::getPlane ( void ) const +{ + return Plane3d(m_center,Vector(0,1,0)); +} + + + diff --git a/engine/shared/library/sharedMath/src/shared/core/Ring.h b/engine/shared/library/sharedMath/src/shared/core/Ring.h new file mode 100644 index 00000000..0c9de3f8 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Ring.h @@ -0,0 +1,78 @@ +// ====================================================================== +// +// Ring.h +// copyright (c) 2001 Sony Online Entertainment +// +// Simple class to represent a 2D Ring in the X-Z plane +// +// This class is only semantically different from a Circle - Circles are +// 2-dimensional entities (i.e. a circle cut from paper) whereas a Ring +// is a 1-dimensional entity (a piece of wire bent into a circle) +// +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_Ring_H +#define INCLUDED_Ring_H + +#include "sharedMath/Vector.h" + +class Range; +class Plane3d; + +// ====================================================================== + +class Ring +{ +public: + + Ring ( Vector const & center, float radius ); + + // ---------- + + Vector const & getCenter ( void ) const; + + float getRadius ( void ) const; + float getRadiusSquared ( void ) const; + + Range getRangeX ( void ) const; + Range getRangeZ ( void ) const; + + Range getLocalRangeX ( void ) const; + + Plane3d getPlane ( void ) const; + +protected: + + Vector m_center; + float m_radius; +}; + +// ---------------------------------------------------------------------- + +inline Ring::Ring ( Vector const & center, float radius ) +: m_center(center), + m_radius(radius) +{ + +} + +inline Vector const & Ring::getCenter ( void ) const +{ + return m_center; +} + +inline float Ring::getRadius ( void ) const +{ + return m_radius; +} + +inline float Ring::getRadiusSquared ( void ) const +{ + return m_radius * m_radius; +} + + +// ---------------------------------------------------------------------- + +#endif + diff --git a/engine/shared/library/sharedMath/src/shared/core/Segment3d.cpp b/engine/shared/library/sharedMath/src/shared/core/Segment3d.cpp new file mode 100644 index 00000000..bd136ee0 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Segment3d.cpp @@ -0,0 +1,38 @@ +// ====================================================================== +// +// Segment3d.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/Segment3d.h" + +#include "sharedMath/Line3d.h" +#include "sharedMath/Range.h" + +Line3d Segment3d::getLine ( void ) const +{ + return Line3d(m_begin,m_end-m_begin); +} + +Line3d Segment3d::getReverseLine ( void ) const +{ + return Line3d(m_end,m_begin-m_end); +} + +Range Segment3d::getRangeX ( void ) const +{ + return Range(m_begin.x,m_end.x); +} + +Range Segment3d::getRangeY ( void ) const +{ + return Range(m_begin.y,m_end.y); +} + +Range Segment3d::getRangeZ ( void ) const +{ + return Range(m_begin.z,m_end.z); +} + diff --git a/engine/shared/library/sharedMath/src/shared/core/Segment3d.h b/engine/shared/library/sharedMath/src/shared/core/Segment3d.h new file mode 100644 index 00000000..a4c6b6f5 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Segment3d.h @@ -0,0 +1,99 @@ +// ====================================================================== +// +// Segment3d.h +// copyright (c) 2001 Sony Online Entertainment +// +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_Segment3d_H +#define INCLUDED_Segment3d_H + +#include "sharedMath/Vector.h" + +class Line3d; +class Range; + +// ---------------------------------------------------------------------- + +class Segment3d +{ +public: + + Segment3d ( Vector const & b, Vector const & e ); + + Vector const & getBegin ( void ) const; + Vector const & getEnd ( void ) const; + + Vector & getBegin ( void ); + Vector & getEnd ( void ); + + Vector getDelta ( void ) const; + Line3d getLine ( void ) const; + Line3d getReverseLine ( void ) const; + + float getLength ( void ) const; + float getLengthSquared ( void ) const; + + Range getRangeX ( void ) const; + Range getRangeY ( void ) const; + Range getRangeZ ( void ) const; + + Vector atParam ( float t ) const; + +protected: + + Vector m_begin; + Vector m_end; +}; + +// ---------- + +inline Segment3d::Segment3d ( Vector const & b, Vector const & e ) +: m_begin(b), m_end(e) +{ +} + +inline Vector const & Segment3d::getBegin ( void ) const +{ + return m_begin; +} + +inline Vector const & Segment3d::getEnd ( void ) const +{ + return m_end; +} + +inline Vector & Segment3d::getBegin ( void ) +{ + return m_begin; +} + +inline Vector & Segment3d::getEnd ( void ) +{ + return m_end; +} + +inline Vector Segment3d::getDelta ( void ) const +{ + return m_end - m_begin; +} + +inline float Segment3d::getLength ( void ) const +{ + return getDelta().magnitude(); +} + +inline float Segment3d::getLengthSquared ( void ) const +{ + return getDelta().magnitudeSquared(); +} + +inline Vector Segment3d::atParam ( float t ) const +{ + return m_begin + (m_end - m_begin) * t; +} + +// ---------------------------------------------------------------------- + +#endif // #ifndef INCLUDED_Segment3d_H + diff --git a/engine/shared/library/sharedMath/src/shared/core/ShapeUtils.cpp b/engine/shared/library/sharedMath/src/shared/core/ShapeUtils.cpp new file mode 100644 index 00000000..c4532067 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/ShapeUtils.cpp @@ -0,0 +1,327 @@ +// ====================================================================== +// +// ShapeUtils.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/ShapeUtils.h" + +#include "sharedMath/MultiShape.h" +#include "sharedMath/Transform.h" +#include "sharedMath/Sphere.h" +#include "sharedMath/Cylinder.h" +#include "sharedMath/OrientedCylinder.h" +#include "sharedMath/AxialBox.h" +#include "sharedMath/YawedBox.h" +#include "sharedMath/OrientedBox.h" +#include "sharedMath/Segment3d.h" +#include "sharedMath/Line3d.h" + +namespace ShapeUtils +{ + +// ---------------------------------------------------------------------- + +MultiShape transform ( MultiShape const & shape, Transform const & tform, float scaleFactor ) +{ + Vector center = tform.rotateTranslate_l2p( shape.getCenter() * scaleFactor ); + + Vector axisX = tform.rotate_l2p( shape.getAxisX() ); + Vector axisY = tform.rotate_l2p( shape.getAxisY() ); + Vector axisZ = tform.rotate_l2p( shape.getAxisZ() ); + + IGNORE_RETURN( axisX.normalize() ); + IGNORE_RETURN( axisY.normalize() ); + IGNORE_RETURN( axisZ.normalize() ); + + // ---------- + + return MultiShape( shape.getBaseType(), + center, + axisX, + axisY, + axisZ, + shape.getExtentX() * scaleFactor, + shape.getExtentY() * scaleFactor, + shape.getExtentZ() * scaleFactor ); +} + +// ---------------------------------------------------------------------- + +Cylinder transform ( Cylinder const & shape, Transform const & tform, float scaleFactor ) +{ + Cylinder temp = shape; + + temp = scale(temp,scaleFactor); + + temp = transform_yt(temp,tform); + + return temp; +} + +OrientedCylinder transform ( OrientedCylinder const & shape, Transform const & tform, float scaleFactor ) +{ + OrientedCylinder temp = shape; + + temp = scale(temp,scaleFactor); + + temp = transform_rt(temp,tform); + + return temp; +} + +Sphere transform ( Sphere const & shape, Transform const & tform, float scaleFactor ) +{ + Sphere temp = shape; + + temp = scale(temp,scaleFactor); + + temp = transform_rt(temp,tform); + + return temp; +} + +AxialBox transform ( AxialBox const & shape, Transform const & tform, float scaleFactor ) +{ + AxialBox temp = shape; + + temp = scale(temp,scaleFactor); + + temp = transform_t(temp,tform); + + return temp; +} + +// ---------------------------------------------------------------------- + +Segment3d transform_p2l ( Segment3d const & seg, Transform const & tform, float scaleFactor ) +{ + Vector begin = tform.rotateTranslate_p2l(seg.getBegin()); + Vector end = tform.rotateTranslate_p2l(seg.getEnd()); + + return Segment3d( begin / scaleFactor, end / scaleFactor ); +} + +Line3d transform_p2l ( Line3d const & line, Transform const & tform, float scaleFactor ) +{ + Vector point = tform.rotateTranslate_p2l(line.getPoint()); + Vector dir = tform.rotate_p2l(line.getNormal()); + + return Line3d( point / scaleFactor, dir ); +} + +// ---------------------------------------------------------------------- +// Transform-shape-to-world methods + +// Translate methods + +Sphere translate ( Sphere const & sphere, Vector const & t ) +{ + Vector center = sphere.getCenter() + t; + + return Sphere(center, sphere.getRadius()); +} + +Cylinder translate ( Cylinder const & cyl, Vector const & t ) +{ + Vector base = cyl.getBase() + t; + float radius = cyl.getRadius(); + float height = cyl.getHeight(); + + return Cylinder(base,radius,height); +} + +AxialBox translate ( AxialBox const & box, Vector const & t ) +{ + Vector min = box.getMin() + t; + Vector max = box.getMax() + t; + + return AxialBox(min,max); +} + +MultiShape translate ( MultiShape const & shape, Vector const & t ) +{ + return MultiShape( shape.getBaseType(), + shape.getShapeType(), + shape.getCenter() + t, + shape.getAxisX(), + shape.getAxisY(), + shape.getAxisZ(), + shape.getExtentX(), + shape.getExtentY(), + shape.getExtentZ() ); +} + +// ---------- + +Sphere transform_t ( Sphere const & sphere, Transform const & t ) +{ + Vector center = t.rotateTranslate_l2p( sphere.getCenter() ); + + return Sphere(center, sphere.getRadius()); +} + +Cylinder transform_t ( Cylinder const & cyl, Transform const & t ) +{ + Vector base = cyl.getBase() + t.getPosition_p(); + float radius = cyl.getRadius(); + float height = cyl.getHeight(); + + return Cylinder(base,radius,height); +} + +AxialBox transform_t ( AxialBox const & box, Transform const & t ) +{ + Vector min = box.getMin() + t.getPosition_p(); + Vector max = box.getMax() + t.getPosition_p(); + + return AxialBox(min,max); +} + +// ---------- +// Yaw-translate methods + +Sphere transform_yt ( Sphere const & sphere, Transform const & t ) +{ + Vector center = t.rotateTranslate_l2p( sphere.getCenter() ); + + return Sphere(center, sphere.getRadius()); +} + +Cylinder transform_yt ( Cylinder const & cyl, Transform const & t ) +{ + Vector base = t.rotateTranslate_l2p( cyl.getBase() ); + + return Cylinder( base, cyl.getRadius(), cyl.getHeight() ); +} + +YawedBox transform_yt ( AxialBox const & box, Transform const & t ) +{ + real yaw = t.getLocalFrameK_p().theta(); + + Vector center = t.rotateTranslate_l2p( box.getCenter() ); + + Vector min = center - box.getDelta(); + Vector max = center + box.getDelta(); + + AxialBox worldBox(min,max); + + return YawedBox(worldBox,yaw); +} + +// ---------- +// Rotate-translate methods + +Sphere transform_rt ( Sphere const & sphere, Transform const & t ) +{ + Vector center = t.rotateTranslate_l2p( sphere.getCenter() ); + + return Sphere(center, sphere.getRadius()); +} + +OrientedCylinder transform_rt ( Cylinder const & cyl, Transform const & t ) +{ + Vector base = t.rotateTranslate_l2p(cyl.getBase()); + Vector axis = t.rotate_l2p( Vector::unitY ); + + return OrientedCylinder ( base, axis, cyl.getRadius(), cyl.getHeight() ); +} + +OrientedCylinder transform_rt ( OrientedCylinder const & cyl, Transform const & t ) +{ + Vector base = t.rotateTranslate_l2p(cyl.getBase()); + Vector axis = t.rotate_l2p(cyl.getAxis()); + + return OrientedCylinder ( base, axis, cyl.getRadius(), cyl.getHeight() ); +} + +OrientedBox transform_rt ( AxialBox const & box, Transform const & t ) +{ + Vector delta = box.getDelta(); + Vector center = t.rotateTranslate_l2p(box.getCenter()); + + Vector xAxis = t.rotate_l2p( Vector::unitX ); + Vector yAxis = t.rotate_l2p( Vector::unitY ); + Vector zAxis = t.rotate_l2p( Vector::unitZ ); + + Vector worldCenter = t.rotateTranslate_l2p( center ); + + OrientedBox temp( worldCenter, xAxis, yAxis, zAxis, delta.x, delta.y, delta.z ); + + return temp; +} + +// ---------- + +Sphere scale ( Sphere const & sphere, float scaleFactor ) +{ + return Sphere( sphere.getCenter() * scaleFactor, + sphere.getRadius() * scaleFactor ); +} + +Cylinder scale ( Cylinder const & cylinder, float scaleFactor ) +{ + return Cylinder( cylinder.getBase() * scaleFactor, + cylinder.getRadius() * scaleFactor, + cylinder.getHeight() * scaleFactor ); +} + +OrientedCylinder scale ( OrientedCylinder const & cylinder, float scaleFactor ) +{ + return OrientedCylinder( cylinder.getBase() * scaleFactor, + cylinder.getAxis(), + cylinder.getRadius() * scaleFactor, + cylinder.getHeight() * scaleFactor ); +} + +AxialBox scale ( AxialBox const & box, float scaleFactor ) +{ + return AxialBox( box.getMin() * scaleFactor, + box.getMax() * scaleFactor ); +} + +YawedBox scale ( YawedBox const & box, float scaleFactor ) +{ + return YawedBox( box.getBase() * scaleFactor, + box.getAxisX(), + box.getAxisZ(), + box.getExtentX() * scaleFactor, + box.getExtentZ() * scaleFactor, + box.getHeight() * scaleFactor ); +} + +OrientedBox scale ( OrientedBox const & box, float scaleFactor ) +{ + return OrientedBox( box.getCenter() * scaleFactor, + box.getAxisX(), + box.getAxisY(), + box.getAxisZ(), + box.getExtentX() * scaleFactor, + box.getExtentY() * scaleFactor, + box.getExtentZ() * scaleFactor ); +} + +// ---------------------------------------------------------------------- + +AxialBox inflate ( AxialBox const & box, float amount ) +{ + return AxialBox( box.getMax() + Vector(amount,amount,amount), box.getMin() - Vector(amount,amount,amount) ); +} + +Sphere inflate ( Sphere const & sphere, float amount ) +{ + return Sphere( sphere.getCenter(), sphere.getRadius() + amount ); +} + +Cylinder inflate ( Cylinder const & cylinder, float amount ) +{ + return Cylinder ( cylinder.getBase() - Vector(0.0f,amount,0.0f), cylinder.getRadius() + amount, cylinder.getHeight() + amount * 2.0f ); +} +// ---------------------------------------------------------------------- + +} // namespace ShapeUtils + + + diff --git a/engine/shared/library/sharedMath/src/shared/core/ShapeUtils.h b/engine/shared/library/sharedMath/src/shared/core/ShapeUtils.h new file mode 100644 index 00000000..d9789194 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/ShapeUtils.h @@ -0,0 +1,119 @@ +// ====================================================================== +// +// ShapeUtils.h +// copyright (c) 2001 Sony Online Entertainment +// +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_ShapeUtils_H +#define INCLUDED_ShapeUtils_H + +class Transform; +class Vector; +class MultiShape; +class Sphere; +class Cylinder; +class OrientedCylinder; +class AxialBox; +class YawedBox; +class OrientedBox; +class Segment3d; +class Line3d; + +// ---------------------------------------------------------------------- + +namespace ShapeUtils +{ + +// ---------- +// Transform the given shape to parent space and enclose it with another shape + +AxialBox EncloseTransform_ABox ( AxialBox const & box, Transform const & tform ); + + +// ---------- + + +MultiShape transform ( MultiShape const & shape, + Transform const & tform, + float scaleFactor = 1.0f ); + +Sphere transform ( Sphere const & sphere, + Transform const & tform, + float scaleFactor = 1.0f ); + +Cylinder transform ( Cylinder const & cylinder, + Transform const & tform, + float scaleFactor = 1.0f ); + +OrientedCylinder transform ( OrientedCylinder const & cylinder, + Transform const & tform, + float scaleFactor = 1.0f ); + +// This will produce the smallest axis-aligned bounding box containing the transformed box + +AxialBox transform ( AxialBox const & box, + Transform const & tform, + float scaleFactor = 1.0f ); + +// ---------------------------------------------------------------------- + +Segment3d transform_p2l ( Segment3d const & seg, + Transform const & tform, + float scaleFactor = 1.0f ); + +Line3d transform_p2l ( Line3d const & line, + Transform const & tform, + float scaleFactor = 1.0f ); + +// ---------------------------------------------------------------------- +// Transform-shape-to-world methods + +// Translate-only methods + +Sphere translate ( Sphere const & sphere, Vector const & t ); +Cylinder translate ( Cylinder const & cyl, Vector const & t ); +AxialBox translate ( AxialBox const & box, Vector const & t ); +MultiShape translate ( MultiShape const & shape, Vector const & t ); + +Sphere transform_t ( Sphere const & sphere, Transform const & t ); +Cylinder transform_t ( Cylinder const & cyl, Transform const & t ); +AxialBox transform_t ( AxialBox const & box, Transform const & t ); + +// ---------- +// Yaw-translate methods + +Sphere transform_yt ( Sphere const & sphere, Transform const & t ); +Cylinder transform_yt ( Cylinder const & cyl, Transform const & t ); +YawedBox transform_yt ( AxialBox const & box, Transform const & t ); + +// ---------- +// Rotate-translate methods + +Sphere transform_rt ( Sphere const & sphere, Transform const & t ); +OrientedCylinder transform_rt ( Cylinder const & cyl, Transform const & t ); +OrientedCylinder transform_rt ( OrientedCylinder const & cyl, Transform const & t ); +OrientedBox transform_rt ( AxialBox const & box, Transform const & t ); + +// ---------- + +Sphere scale ( Sphere const & sphere, float scaleFactor ); +Cylinder scale ( Cylinder const & cylinder, float scaleFactor ); +OrientedCylinder scale ( OrientedCylinder const & cylinder, float scaleFactor ); +AxialBox scale ( AxialBox const & box, float scaleFactor ); +YawedBox scale ( YawedBox const & box, float scaleFactor ); +OrientedBox scale ( OrientedBox const & box, float scaleFactor ); + +// ---------- +// Other useful methods + +AxialBox inflate ( AxialBox const & B, float amount ); +Sphere inflate ( Sphere const & S, float amount ); +Cylinder inflate ( Cylinder const & C, float amount ); + +}; // namespace ShapeUtils + +// ====================================================================== + +#endif // #ifndef INCLUDED_ShapeUtils_H + diff --git a/engine/shared/library/sharedMath/src/shared/core/Torus.cpp b/engine/shared/library/sharedMath/src/shared/core/Torus.cpp new file mode 100644 index 00000000..6cf3a4f1 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Torus.cpp @@ -0,0 +1,42 @@ +// ====================================================================== +// +// Torus.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/Torus.h" + + +Vector Torus::transformToLocal( Vector const & V ) const +{ + return rotateToLocal( V - m_center ); +} + +Vector Torus::transformToWorld ( Vector const & V ) const +{ + return rotateToWorld(V) + m_center; +} + +Vector Torus::rotateToLocal ( Vector const & V ) const +{ + Vector temp; + + temp.x = V.dot(m_tangent); + temp.y = V.dot(m_axis); + temp.z = V.dot(m_binormal); + + return temp; +} + +Vector Torus::rotateToWorld ( Vector const & V ) const +{ + Vector temp = Vector::zero; + + temp += m_tangent * V.x; + temp += m_axis * V.y; + temp += m_binormal * V.z; + + return temp; +} diff --git a/engine/shared/library/sharedMath/src/shared/core/Torus.h b/engine/shared/library/sharedMath/src/shared/core/Torus.h new file mode 100644 index 00000000..b00eba55 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Torus.h @@ -0,0 +1,103 @@ +// ====================================================================== +// +// Torus.h +// copyright (c) 2001 Sony Online Entertainment +// +// Simple class to represent a 2D Torus in the X-Z plane +// +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_Torus_H +#define INCLUDED_Torus_H + +#include "sharedMath/Vector.h" + +// ====================================================================== + +class Torus +{ +public: + + Torus ( Vector const & center, float majorRadius, float minorRadius ); + Torus ( Vector const & center, Vector const & axis, float majorRadius, float minorRadius ); + + // ---------- + + Vector const & getCenter ( void ) const; + Vector const & getAxis ( void ) const; + + float getMajorRadius ( void ) const; + float getMinorRadius ( void ) const; + + Vector transformToLocal ( Vector const & V ) const; + Vector transformToWorld ( Vector const & V ) const; + + Vector rotateToLocal ( Vector const & V ) const; + Vector rotateToWorld ( Vector const & V ) const; + + bool isOriented ( void ) const; + +protected: + + Vector m_center; + + Vector m_axis; + Vector m_tangent; + Vector m_binormal; + + float m_majorRadius; + float m_minorRadius; +}; + +// ---------------------------------------------------------------------- + +inline Torus::Torus ( Vector const & center, float majorRadius, float minorRadius ) +: m_center(center), + m_axis(0,1,0), + m_tangent(1,0,0), + m_binormal(0,0,1), + m_majorRadius(majorRadius), + m_minorRadius(minorRadius) +{ +} + +inline Torus::Torus ( Vector const & center, Vector const & axis, float majorRadius, float minorRadius ) +: m_center(center), + m_axis(axis), + + m_majorRadius(majorRadius), + m_minorRadius(minorRadius) +{ + m_tangent = m_axis.cross(Vector(0,0,1)); + m_binormal = m_tangent.cross(m_axis); +} + +inline Vector const & Torus::getCenter ( void ) const +{ + return m_center; +} + +inline Vector const & Torus::getAxis ( void ) const +{ + return m_axis; +} + +inline float Torus::getMajorRadius ( void ) const +{ + return m_majorRadius; +} + +inline float Torus::getMinorRadius ( void ) const +{ + return m_minorRadius; +} + +inline bool Torus::isOriented ( void ) const +{ + return fabs(m_axis.y - 1.0f) > 0.00001f; +} + +// ---------------------------------------------------------------------- + +#endif + diff --git a/engine/shared/library/sharedMath/src/shared/core/Triangle2d.cpp b/engine/shared/library/sharedMath/src/shared/core/Triangle2d.cpp new file mode 100644 index 00000000..5ec172cb --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Triangle2d.cpp @@ -0,0 +1,10 @@ +// ====================================================================== +// +// Triangle2d.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +//#include "sharedMath/Triangle2d.h" + diff --git a/engine/shared/library/sharedMath/src/shared/core/Triangle2d.h b/engine/shared/library/sharedMath/src/shared/core/Triangle2d.h new file mode 100644 index 00000000..d6f98d0e --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Triangle2d.h @@ -0,0 +1,102 @@ +// ====================================================================== +// +// Triangle2d.h +// copyright (c) 2001 Sony Online Entertainment +// +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_Triangle2d_H +#define INCLUDED_Triangle2d_H + +#include "sharedMath/Vector2d.h" + +// ====================================================================== +// 2d Triangle + +class Triangle2d +{ +public: + + Triangle2d( Vector2d const & a, Vector2d const & b, Vector2d const & c ); + Triangle2d(); + + // ---------- + + Vector2d const & getCorner ( int i ) const; + void setCorner ( int i, Vector2d const & newCorner ); + + Vector2d const & getCornerA ( void ) const; + Vector2d const & getCornerB ( void ) const; + Vector2d const & getCornerC ( void ) const; + + void setCornerA ( Vector2d const & newCorner ); + void setCornerB ( Vector2d const & newCorner ); + void setCornerC ( Vector2d const & newCorner ); + + // ---------- + +protected: + + Vector2d m_cornerA; + Vector2d m_cornerB; + Vector2d m_cornerC; +}; + +// ---------- + +inline Triangle2d::Triangle2d( Vector2d const & a, Vector2d const & b, Vector2d const & c ) +{ + m_cornerA = a; + m_cornerB = b; + m_cornerC = c; +} + +inline Triangle2d::Triangle2d() +{ +} + +inline Vector2d const & Triangle2d::getCorner ( int i ) const +{ + return (&m_cornerA)[i % 3]; +} + +inline void Triangle2d::setCorner( int i, Vector2d const & newCorner ) +{ + (&m_cornerA)[i%3] = newCorner; +} + +inline Vector2d const & Triangle2d::getCornerA ( void ) const +{ + return m_cornerA; +} + +inline Vector2d const & Triangle2d::getCornerB ( void ) const +{ + return m_cornerB; +} + +inline Vector2d const & Triangle2d::getCornerC ( void ) const +{ + return m_cornerC; +} + +inline void Triangle2d::setCornerA ( Vector2d const & newCorner ) +{ + m_cornerA = newCorner; +} + +inline void Triangle2d::setCornerB ( Vector2d const & newCorner ) +{ + m_cornerB = newCorner; +} + +inline void Triangle2d::setCornerC ( Vector2d const & newCorner ) +{ + m_cornerC = newCorner; +} + + + +// ---------------------------------------------------------------------- + +#endif // #ifdef INCLUDED_Triangle2d_H \ No newline at end of file diff --git a/engine/shared/library/sharedMath/src/shared/core/Triangle3d.cpp b/engine/shared/library/sharedMath/src/shared/core/Triangle3d.cpp new file mode 100644 index 00000000..58c4204d --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Triangle3d.cpp @@ -0,0 +1,200 @@ +// ====================================================================== +// +// Triangle3d.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/Triangle3d.h" + +#include "sharedMath/Line3d.h" +#include "sharedMath/Plane3d.h" +#include "sharedMath/Segment3d.h" + +// ---------- + +Triangle3d::Triangle3d( Vector const & a, Vector const & b, Vector const & c ) +: m_cornerA(a), + m_cornerB(b), + m_cornerC(c), + m_normal() +{ + calcNormal(); +} + +Triangle3d::Triangle3d() +: m_cornerA(), + m_cornerB(), + m_cornerC(), + m_normal() +{ +} + +Vector const & Triangle3d::getCorner ( int i ) const +{ + return (&m_cornerA)[i % 3]; +} + +void Triangle3d::setCorner ( int i, Vector const & newCorner ) +{ + (&m_cornerA)[i % 3] = newCorner; + + calcNormal(); +} + +Vector const & Triangle3d::getCornerA ( void ) const +{ + return m_cornerA; +} + +Vector const & Triangle3d::getCornerB ( void ) const +{ + return m_cornerB; +} + +Vector const & Triangle3d::getCornerC ( void ) const +{ + return m_cornerC; +} + +void Triangle3d::setCornerA ( Vector const & newCorner ) +{ + m_cornerA = newCorner; + + calcNormal(); +} + +void Triangle3d::setCornerB ( Vector const & newCorner ) +{ + m_cornerB = newCorner; + + calcNormal(); +} + +void Triangle3d::setCornerC ( Vector const & newCorner ) +{ + m_cornerC = newCorner; + + calcNormal(); +} + + +Vector Triangle3d::getNormal(void) const +{ + return m_normal; +} + +real Triangle3d::getArea ( void ) const +{ + return ((getCornerB()-getCornerA()).cross(getCornerC()-getCornerA())).magnitude() * 0.5f; +} + +bool Triangle3d::isDegenerate ( void ) const +{ + real area = getArea(); + + return area < 0.000001f; // one square millimeter +} + +Plane3d Triangle3d::getPlane ( void ) const +{ + return Plane3d(getCornerA(),getNormal()); +} + +// ---------- + +Vector Triangle3d::getEdgeDir ( int whichEdge ) const +{ + return getCorner(whichEdge+1) - getCorner(whichEdge); +} + +Vector Triangle3d::getEdgeDir0 ( void ) const +{ + return getCornerB() - getCornerA(); +} + +Vector Triangle3d::getEdgeDir1 ( void ) const +{ + return getCornerC() - getCornerB(); +} + +Vector Triangle3d::getEdgeDir2 ( void ) const +{ + return getCornerA() - getCornerC(); +} + +// ---------- + +Segment3d Triangle3d::getEdgeSegment ( int whichSegment ) const +{ + return Segment3d(getCorner(whichSegment),getCorner(whichSegment+1)); +} + +Segment3d Triangle3d::getEdgeSegment0 ( void ) const +{ + return Segment3d(getCornerA(),getCornerB()); +} + +Segment3d Triangle3d::getEdgeSegment1 ( void ) const +{ + return Segment3d(getCornerB(),getCornerC()); +} + +Segment3d Triangle3d::getEdgeSegment2 ( void ) const +{ + return Segment3d(getCornerC(),getCornerA()); +} + +// ---------- + +Line3d Triangle3d::getEdgeLine ( int whichEdge ) const +{ + return Line3d(getCorner(whichEdge),getEdgeDir(whichEdge)); +} + +Line3d Triangle3d::getEdgeLine0 ( void ) const +{ + return Line3d(getCornerA(),getEdgeDir0()); +} + +Line3d Triangle3d::getEdgeLine1 ( void ) const +{ + return Line3d(getCornerB(),getEdgeDir1()); +} + +Line3d Triangle3d::getEdgeLine2 ( void ) const +{ + return Line3d(getCornerC(),getEdgeDir2()); +} + +// ---------- + +void Triangle3d::flip ( void ) +{ + Vector temp = m_cornerC; + m_cornerC = m_cornerB; + m_cornerB = temp; +} + +// ---------- + +bool Triangle3d::isFacing ( Vector const & dir ) const +{ + return getNormal().dot(dir) > 0; +} + +// ---------- + +// assumes ***CLOCKWISE*** vertex winding + +void Triangle3d::calcNormal ( void ) +{ + Vector temp = getEdgeDir0().cross( getEdgeDir1() ); + + IGNORE_RETURN( temp.normalize() ); + + m_normal = temp; +} + + diff --git a/engine/shared/library/sharedMath/src/shared/core/Triangle3d.h b/engine/shared/library/sharedMath/src/shared/core/Triangle3d.h new file mode 100644 index 00000000..c28b818a --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/Triangle3d.h @@ -0,0 +1,85 @@ +// ====================================================================== +// +// Triangle3d.h +// copyright (c) 2001 Sony Online Entertainment +// +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_Triangle3d_H +#define INCLUDED_Triangle3d_H + +#include "sharedMath/Vector.h" + +class Line3d; +class Plane3d; +class Segment3d; + +// ====================================================================== +// 3d Triangle3d + +// ***CLOCKWISE*** vertex winding! + +class Triangle3d +{ +public: + + Triangle3d( Vector const & a, Vector const & b, Vector const & c ); + Triangle3d(); + + // ---------- + + Vector const & getCorner ( int i ) const; + Vector const & getCornerA ( void ) const; + Vector const & getCornerB ( void ) const; + Vector const & getCornerC ( void ) const; + + void setCorner ( int i, Vector const & newCorner ); + void setCornerA ( Vector const & newCorner ); + void setCornerB ( Vector const & newCorner ); + void setCornerC ( Vector const & newCorner ); + + Vector getNormal ( void ) const; + + // ---------- + + real getArea ( void ) const; + bool isDegenerate ( void ) const; + + bool isFacing ( Vector const & dir ) const; + void flip ( void ); // Swaps vertices B and C, so that the triangle will face the other direction + + // ---------- + + Plane3d getPlane ( void ) const; + + Vector getEdgeDir ( int whichEdge ) const; + Vector getEdgeDir0 ( void ) const; + Vector getEdgeDir1 ( void ) const; + Vector getEdgeDir2 ( void ) const; + + Segment3d getEdgeSegment ( int whichEdge ) const; + Segment3d getEdgeSegment0 ( void ) const; + Segment3d getEdgeSegment1 ( void ) const; + Segment3d getEdgeSegment2 ( void ) const; + + Line3d getEdgeLine ( int whichEdge ) const; + Line3d getEdgeLine0 ( void ) const; + Line3d getEdgeLine1 ( void ) const; + Line3d getEdgeLine2 ( void ) const; + + // ---------- + +protected: + + void calcNormal ( void ); + + Vector m_cornerA; + Vector m_cornerB; + Vector m_cornerC; + Vector m_normal; +}; + +// ---------------------------------------------------------------------- + +#endif + diff --git a/engine/shared/library/sharedMath/src/shared/core/YawedBox.cpp b/engine/shared/library/sharedMath/src/shared/core/YawedBox.cpp new file mode 100644 index 00000000..67df82e5 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/YawedBox.cpp @@ -0,0 +1,102 @@ +// ====================================================================== +// +// YawedBox.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/YawedBox.h" + +#include "sharedMath/Transform.h" +#include "sharedMath/AxialBox.h" +#include "sharedMath/Range.h" + +YawedBox::YawedBox ( AxialBox const & box, float yaw ) +: m_base ( box.getBase() ), + m_axisX ( box.getAxisX() ), + m_axisZ ( box.getAxisZ() ), + m_extentX ( box.getExtentX() ), + m_extentZ ( box.getExtentZ() ), + m_height ( box.getHeight() ) +{ + float c = cos(yaw); + float s = sin(yaw); + + m_axisX = Vector( c, 0.0f, -s ); + m_axisZ = Vector( s, 0.0f, c ); + +} + +// ---------------------------------------------------------------------- + +Range YawedBox::getRangeY ( void ) const +{ + float min = getBase().y; + float max = min + getHeight(); + + return Range(min,max); +} + +// ---------------------------------------------------------------------- + +AxialBox YawedBox::getLocalShape ( void ) const +{ + return AxialBox( Vector( -getExtentX(), -getExtentY(), -getExtentZ() ), + Vector( getExtentX(), getExtentY(), getExtentZ() ) ); +} + +Transform YawedBox::getTransform_l2p ( void ) const +{ + Transform temp; + + temp.setLocalFrameIJK_p( m_axisX, Vector::unitY, m_axisZ ); + temp.move_p( m_base ); + + return temp; +} + +Transform YawedBox::getTransform_p2l ( void ) const +{ + Transform temp; + + temp.invert(getTransform_l2p()); + + return temp; +} + + +Vector YawedBox::transformToLocal ( Vector const & V ) const +{ + return rotateToLocal(V - getCenter()); +} + +Vector YawedBox::transformToWorld ( Vector const & V ) const +{ + return rotateToWorld(V) + getCenter(); +} + +Vector YawedBox::rotateToLocal ( Vector const & V ) const +{ + Vector temp; + + temp.x = V.dot(getAxisX()); + temp.y = V.dot(getAxisY()); + temp.z = V.dot(getAxisZ()); + + return temp; +} + +Vector YawedBox::rotateToWorld ( Vector const & V ) const +{ + Vector temp = Vector::zero; + + temp += getAxisX() * V.x; + temp += getAxisY() * V.y; + temp += getAxisZ() * V.z; + + return temp; +} + +// ---------------------------------------------------------------------- + diff --git a/engine/shared/library/sharedMath/src/shared/core/YawedBox.h b/engine/shared/library/sharedMath/src/shared/core/YawedBox.h new file mode 100644 index 00000000..edf78721 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/core/YawedBox.h @@ -0,0 +1,173 @@ +// ====================================================================== +// +// YawedBox.h +// copyright (c) 2001 Sony Online Entertainment +// +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_YawedBox_H +#define INCLUDED_YawedBox_H + +#include "sharedMath/Vector.h" + +class AxialBox; +class Range; +class Transform; + +// ====================================================================== + +class YawedBox +{ +public: + + YawedBox(); + YawedBox( AxialBox const & box, float yaw ); + YawedBox( Vector const & base, Vector const & axisX, Vector const & axisZ, float extentX, float extentZ, float height ); + + // ---------- + + Range getRangeY ( void ) const; + + Vector const & getBase ( void ) const; + + float getHeight ( void ) const; + + Vector getCorner ( int whichCorner ) const; + + // ---------- + + Vector getCenter ( void ) const; + + Vector const & getAxisX ( void ) const; + Vector const & getAxisY ( void ) const; + Vector const & getAxisZ ( void ) const; + + float getExtentX ( void ) const; + float getExtentY ( void ) const; + float getExtentZ ( void ) const; + + // ---------- + + AxialBox getLocalShape ( void ) const; + + Transform getTransform_l2p ( void ) const; + Transform getTransform_p2l ( void ) const; + + Vector transformToLocal ( Vector const & V ) const; + Vector transformToWorld ( Vector const & V ) const; + + Vector rotateToLocal ( Vector const & V ) const; + Vector rotateToWorld ( Vector const & V ) const; + + // ---------- + +protected: + + Vector m_base; + + Vector m_axisX; + Vector m_axisZ; + + float m_extentX; + float m_extentZ; + + float m_height; +}; + +// ---------------------------------------------------------------------- + +inline YawedBox::YawedBox ( Vector const & base, + Vector const & axisX, + Vector const & axisZ, + float extentX, + float extentZ, + float height ) +: m_base(base), + m_axisX(axisX), + m_axisZ(axisZ), + m_extentX(extentX), + m_extentZ(extentZ), + m_height(height) +{ +} + +// ---------------------------------------------------------------------- + +inline Vector const & YawedBox::getBase ( void ) const +{ + return m_base; +} + +inline float YawedBox::getHeight ( void ) const +{ + return m_height; +} + +inline Vector YawedBox::getCorner ( int whichCorner ) const +{ + // These corners are ordered so that the first 4 are on the bottom of the box + + Vector X = m_axisX * m_extentX; + Vector Y = Vector::unitY * m_height; + Vector Z = m_axisZ * m_extentZ; + + switch(whichCorner) + { + case 0: return m_base - X - Z; + case 1: return m_base + X - Z; + case 2: return m_base - X + Z; + case 3: return m_base + X + Z; + case 4: return m_base - X - Z + Y; + case 5: return m_base + X - Z + Y; + case 6: return m_base - X + Z + Y; + case 7: return m_base + X + Z + Y; + + default: return Vector(0,0,0); + } +} + +// ---------------------------------------------------------------------- + +inline Vector YawedBox::getCenter ( void ) const +{ + return getBase() + Vector(0,getExtentY(),0); +} + +// ---------- + +inline Vector const & YawedBox::getAxisX ( void ) const +{ + return m_axisX; +} + +inline Vector const & YawedBox::getAxisY ( void ) const +{ + return Vector::unitY; +} + +inline Vector const & YawedBox::getAxisZ ( void ) const +{ + return m_axisZ; +} + +// ---------- + +inline float YawedBox::getExtentX ( void ) const +{ + return m_extentX; +} + +inline float YawedBox::getExtentY ( void ) const +{ + return getHeight() / 2.0f; +} + +inline float YawedBox::getExtentZ ( void ) const +{ + return m_extentZ; +} + +// ====================================================================== + +#endif + diff --git a/engine/shared/library/sharedMath/src/shared/debug/DebugShapeRenderer.cpp b/engine/shared/library/sharedMath/src/shared/debug/DebugShapeRenderer.cpp new file mode 100644 index 00000000..3e4c8d34 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/debug/DebugShapeRenderer.cpp @@ -0,0 +1,152 @@ +// ====================================================================== +// +// DebugShapeRenderer.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/DebugShapeRenderer.h" + +#include "sharedMath/Transform.h" + +static DebugShapeRenderer::DebugShapeRendererFactory * gs_factory = NULL; + +// ---------------------------------------------------------------------- + +DebugShapeRenderer::DebugShapeRenderer() +: m_depthTest( true ), + m_worldSpace( false ), + m_applyScale( true ), + m_color( VectorArgb::solidWhite ), + m_overrideColor( VectorArgb::solidRed), + m_override( false ) +{ +} + +DebugShapeRenderer::~DebugShapeRenderer() +{ +} + +Vector DebugShapeRenderer::getScale ( void ) const +{ + return Vector::xyz111; +} + +Transform DebugShapeRenderer::getTransform ( void ) const +{ + return Transform::identity; +} + +void DebugShapeRenderer::setColor ( VectorArgb const & color ) +{ + m_color = color; +} + +void DebugShapeRenderer::setOverrideColor ( bool override, VectorArgb const & color ) +{ + m_override = override; + m_overrideColor = color; +} + +VectorArgb DebugShapeRenderer::getColor ( void ) const +{ + if(m_override) + { + return m_overrideColor; + } + else + { + return m_color; + } +} + +void DebugShapeRenderer::setDepthTest ( bool enabled ) +{ + m_depthTest = enabled; +} + +void DebugShapeRenderer::setWorldSpace ( bool worldSpace ) +{ + m_worldSpace = worldSpace; +} + +void DebugShapeRenderer::setApplyScale ( bool applyScale ) +{ + m_applyScale = applyScale; +} + +void DebugShapeRenderer::drawFrame ( float ) +{ +} + +void DebugShapeRenderer::drawSphere ( Sphere const &, int ) +{ +} + +void DebugShapeRenderer::drawCylinder ( Cylinder const &, int ) +{ +} + +void DebugShapeRenderer::drawOCylinder ( OrientedCylinder const &, int ) +{ +} + +void DebugShapeRenderer::drawBox ( AxialBox const & ) +{ +} + +void DebugShapeRenderer::drawYBox ( YawedBox const & ) +{ +} + +void DebugShapeRenderer::drawOBox ( OrientedBox const & ) +{ +} + +void DebugShapeRenderer::drawMesh ( IndexedTriangleList const * ) +{ +} + +void DebugShapeRenderer::drawMeshNormals ( IndexedTriangleList const * ) +{ +} + +void DebugShapeRenderer::drawLine ( Vector const & , Vector const & ) +{ +} + +void DebugShapeRenderer::drawLineList ( VectorVec const & ) +{ +} + +void DebugShapeRenderer::drawLineList ( VectorVec const & verts, VectorArgb const & color ) +{ + setColor(color); + drawLineList(verts); +} + +void DebugShapeRenderer::drawPolygon ( VectorVec const & ) +{ +} + +void DebugShapeRenderer::drawOctahedron ( Vector const &, float ) +{ +} + +void DebugShapeRenderer::drawXZCircle ( Vector const &, float ) +{ +} + +void DebugShapeRenderer::setFactory ( DebugShapeRenderer::DebugShapeRendererFactory * factory ) +{ + gs_factory = factory; +} + +DebugShapeRenderer * DebugShapeRenderer::create ( Object const * object ) +{ + if(gs_factory == NULL) + return NULL; + + return gs_factory(object); +} diff --git a/engine/shared/library/sharedMath/src/shared/debug/DebugShapeRenderer.h b/engine/shared/library/sharedMath/src/shared/debug/DebugShapeRenderer.h new file mode 100644 index 00000000..7ff847a0 --- /dev/null +++ b/engine/shared/library/sharedMath/src/shared/debug/DebugShapeRenderer.h @@ -0,0 +1,105 @@ +// ====================================================================== +// +// DebugShapeRenderer.h +// copyright (c) 2001 Sony Online Entertainment +// +// ---------------------------------------------------------------------- + +#ifndef INCLUDED_DebugShapeRenderer_H +#define INCLUDED_DebugShapeRenderer_H + +#include "sharedMath/VectorArgb.h" + +class Sphere; +class Cylinder; +class OrientedCylinder; +class AxialBox; +class YawedBox; +class OrientedBox; +class IndexedTriangleList; +class Vector; +class Object; +class Transform; + +typedef stdvector::fwd VectorVec; + +class DebugShapeRenderer +{ +public: + + DebugShapeRenderer(); + virtual ~DebugShapeRenderer(); + + virtual Vector getScale ( void ) const; + virtual Transform getTransform ( void ) const; + + virtual void setColor ( VectorArgb const & color ); + virtual void setOverrideColor( bool override, VectorArgb const & color = VectorArgb::solidRed ); + + virtual VectorArgb getColor ( void ) const; + + virtual void setDepthTest ( bool enabled ); + virtual void setWorldSpace ( bool worldSpace ); + virtual void setApplyScale ( bool applyScale ); // if true, parent object's scale factor will be applied to debug shapes before rendering + + virtual void drawFrame ( float radius ); + + virtual void drawSphere ( Sphere const & sphere, int tess = 16 ); + virtual void drawCylinder ( Cylinder const & cylinder, int tess = 16 ); + virtual void drawOCylinder ( OrientedCylinder const & cylinder, int tess = 16 ); + virtual void drawBox ( AxialBox const & box ); + virtual void drawYBox ( YawedBox const & box ); + virtual void drawOBox ( OrientedBox const & box ); + + virtual void drawMesh ( IndexedTriangleList const * mesh ); + virtual void drawMeshNormals ( IndexedTriangleList const * mesh ); + virtual void drawLine ( Vector const & begin, Vector const & end ); + virtual void drawLineList ( VectorVec const & verts ); + virtual void drawLineList ( VectorVec const & verts, VectorArgb const & color ); + virtual void drawPolygon ( VectorVec const & verts ); + virtual void drawOctahedron ( Vector const & center, float radius ); + virtual void drawXZCircle ( Vector const & center, float radius ); + + // ---------- + + void draw ( Sphere const & s ); + void draw ( Cylinder const & s ); + void draw ( OrientedCylinder const & s ); + void draw ( AxialBox const & s ); + void draw ( YawedBox const & s ); + void draw ( OrientedBox const & s ); + + // ---------- + + typedef DebugShapeRenderer * (DebugShapeRendererFactory)( Object const * object ); + + static void setFactory( DebugShapeRendererFactory * factory ); + + static DebugShapeRenderer * create( Object const * object ); + +protected: + + bool m_depthTest; + bool m_worldSpace; + bool m_applyScale; + +private: + + VectorArgb m_color; + VectorArgb m_overrideColor; + bool m_override; + +}; + +// ---------------------------------------------------------------------- + +inline void DebugShapeRenderer::draw ( Sphere const & s ) { drawSphere(s); } +inline void DebugShapeRenderer::draw ( Cylinder const & s ) { drawCylinder(s); } +inline void DebugShapeRenderer::draw ( OrientedCylinder const & s ) { drawOCylinder(s); } +inline void DebugShapeRenderer::draw ( AxialBox const & s ) { drawBox(s); } +inline void DebugShapeRenderer::draw ( YawedBox const & s ) { drawYBox(s); } +inline void DebugShapeRenderer::draw ( OrientedBox const & s ) { drawOBox(s); } + +// ---------------------------------------------------------------------- + +#endif diff --git a/engine/shared/library/sharedMath/src/win32/FirstSharedMath.cpp b/engine/shared/library/sharedMath/src/win32/FirstSharedMath.cpp new file mode 100644 index 00000000..5f04bd2a --- /dev/null +++ b/engine/shared/library/sharedMath/src/win32/FirstSharedMath.cpp @@ -0,0 +1,8 @@ +// ====================================================================== +// +// FirstMath.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" diff --git a/engine/shared/library/sharedMath/src/win32/SseMath.cpp b/engine/shared/library/sharedMath/src/win32/SseMath.cpp new file mode 100644 index 00000000..11624aab --- /dev/null +++ b/engine/shared/library/sharedMath/src/win32/SseMath.cpp @@ -0,0 +1,430 @@ +// ====================================================================== +// +// SseMath.cpp +// Copyright 2002 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/SseMath.h" + +#include "sharedMath/Transform.h" +#include "sharedMath/Vector.h" + +// ====================================================================== + +#define SSE_ALIGN __declspec(align(16)) +#define SSE_VARIABLE_COUNT 5 + +// ====================================================================== + +namespace +{ + SSE_ALIGN float sseVariable[SSE_VARIABLE_COUNT][4]; +} + +// ====================================================================== +/** + * Retrieve whether the hardware can do SSE math. + * + * @return true if SSE math processing is available; false otherwise. + */ + +bool SseMath::canDoSseMath() +{ +#if 0 + return false; +#else + //-- First check the CPUID instruction. If it raises an exception, + // the CPUID instruction doesn't exist and SSE math support is not available. + bool cpuHasSse = false; + bool cpuHasSaveRestore = false; + + uint32 featureBits; + +#if 0 + bool osSupportsSaveRestore = false; + bool osSimdExceptionSupport = false; + bool x87EmulationDisabled = false; + + uint32 controlRegister4; + uint32 controlRegister0; +#endif + + try + { + __asm { + //-- Get features bits. + mov eax, 1 + cpuid + + mov featureBits, edx + +#if 0 + //-- Get control registers. + mov ecx, CR4 + mov controlRegister4, ecx + + mov ecx, CR0 + mov controlRegister0, ecx +#endif + } + + cpuHasSse = ((featureBits & 0x02000000) != 0); //lint !e530 // featureBits not initialized - yes it is, in the asm + cpuHasSaveRestore = ((featureBits & 0x01000000) != 0); + +#if 0 + osSupportsSaveRestore = ((controlRegister4 & 0x00000200) != 0); + osSimdExceptionSupport = ((controlRegister4 & 0x00000400) != 0); + x87EmulationDisabled = ((controlRegister0 & 0x00000004) == 0); +#endif + } + catch (...) + { //lint !e1775 // catch block does not catch any declared exceptions + } + +#if 1 + return cpuHasSse && cpuHasSaveRestore; +#else + return cpuHasSse && cpuHasSaveRestore && osSupportsSaveRestore && osSimdExceptionSupport && x87EmulationDisabled; +#endif +#endif +} + +// ---------------------------------------------------------------------- + +Vector SseMath::rotateTranslateScale_l2p(const Transform &transform, const Vector &vector, float scale) +{ + // NOTE: technically, my xmm register data contents comments are listing items in reverse order from how INTEL docs list them, left most val is really least significant value. + + __asm { + //-- Keep track of ebx. Client is crashing if I trash this. + push ebx + + //-- Load up matrix. + mov ebx, transform + + movaps xmm0, [ebx + 0] // xmm0 = a1 a2 a3 a4 + movaps xmm1, [ebx + 16] // xmm1 = b1 b2 b3 b4 + movaps xmm2, [ebx + 32] // xmm2 = c1 c2 c3 c4 + } + + //-- Prepare source vector. + sseVariable[0][0] = vector.x; + sseVariable[0][1] = vector.y; + sseVariable[0][2] = vector.z; + sseVariable[0][3] = 1.0f; + + __asm { + //-- Load up the source vector. + mov ebx, offset sseVariable + + movaps xmm3, [ebx] // xmm3 = sx sy sz 1 + + //-- Copy source to workspaces. + movaps xmm4, xmm3 // xmm4 = sx sy sz 1 + movaps xmm5, xmm3 // xmm5 = sx sy sz 1 + } + + //-- Prepare the scale vector. + __asm { + movss xmm6, scale // xmm6 = scale ? ? ? + shufps xmm6, xmm6, 0x00 // xmm6 = scale scale + movlhps xmm6, xmm6 // xmm6 = scale scale scale scale + + //-- Do the transform multiplies. + mulps xmm3, xmm0 // xmm3 = a1*sx a2*sy a3*sz a4 + mulps xmm4, xmm1 // xmm4 = b1*sx b2*sy b3*sz b4 + mulps xmm5, xmm2 // xmm5 = c1*sx c2*sy c3*sz c4 + + //-- Do the scale multiplies. + mulps xmm3, xmm6 // xmm3 = a1*sx*scale a2*sy*scale a3*sz*scale a4*scale + mulps xmm4, xmm6 // xmm4 = b1*sx*scale b2*sy*scale b3*sz*scale b4*scale + mulps xmm5, xmm6 // xmm5 = c1*sx*scale c2*sy*scale c3*sz*scale c4*scale + + //-- Save out data. + movaps [ebx + 32], xmm3 + movaps [ebx + 48], xmm4 + movaps [ebx + 64], xmm5 + + //-- Restore EBX + pop ebx + } + + // @todo consider twizzling/detwizzling to be able to perform add in sse. + return Vector( + sseVariable[2][0] + sseVariable[2][1] + sseVariable[2][2] + sseVariable[2][3], + sseVariable[3][0] + sseVariable[3][1] + sseVariable[3][2] + sseVariable[3][3], + sseVariable[4][0] + sseVariable[4][1] + sseVariable[4][2] + sseVariable[4][3]); +} //lint !e715 // scale/transform not referenced - it's in the asm + +// ---------------------------------------------------------------------- + +Vector SseMath::rotateScale_l2p(const Transform &transform, const Vector &vector, float scale) +{ +#if 0 + // @todo do the real thing. + return transform.rotate_l2p(vector) * scale; +#else + + // NOTE: technically, my xmm register data contents comments are listing items in reverse order from how INTEL docs list them, left most val is really least significant value. + + __asm { + //-- Keep track of ebx. Client is crashing if I trash this. + push ebx + + //-- Load up matrix. + mov ebx, transform + + movaps xmm0, [ebx + 0] // xmm0 = a1 a2 a3 a4 + movaps xmm1, [ebx + 16] // xmm1 = b1 b2 b3 b4 + movaps xmm2, [ebx + 32] // xmm2 = c1 c2 c3 c4 + } + + //-- Prepare source vector. + sseVariable[0][0] = vector.x; + sseVariable[0][1] = vector.y; + sseVariable[0][2] = vector.z; + sseVariable[0][3] = 0.0f; + + __asm { + //-- Load up the source vector. + mov ebx, offset sseVariable + + movaps xmm3, [ebx] // xmm3 = sx sy sz 1 + + //-- Copy source to workspaces. + movaps xmm4, xmm3 // xmm4 = sx sy sz 1 + movaps xmm5, xmm3 // xmm5 = sx sy sz 1 + } + + //-- Prepare the scale vector. + __asm { + movss xmm6, scale // xmm6 = scale ? ? ? + shufps xmm6, xmm6, 0x00 // xmm6 = scale scale + movlhps xmm6, xmm6 // xmm6 = scale scale scale scale + + //-- Do the transform multiplies. + mulps xmm3, xmm0 // xmm3 = a1*sx a2*sy a3*sz 0 + mulps xmm4, xmm1 // xmm4 = b1*sx b2*sy b3*sz 0 + mulps xmm5, xmm2 // xmm5 = c1*sx c2*sy c3*sz 0 + + //-- Do the scale multiplies. + mulps xmm3, xmm6 // xmm3 = a1*sx*scale a2*sy*scale a3*sz*scale 0 + mulps xmm4, xmm6 // xmm4 = b1*sx*scale b2*sy*scale b3*sz*scale 0 + mulps xmm5, xmm6 // xmm5 = c1*sx*scale c2*sy*scale c3*sz*scale 0 + + //-- Save out data. + movaps [ebx + 32], xmm3 + movaps [ebx + 48], xmm4 + movaps [ebx + 64], xmm5 + + //-- Restore EBX + pop ebx + } + + // @todo consider twizzling/detwizzling to be able to perform add in sse. + return Vector( + sseVariable[2][0] + sseVariable[2][1] + sseVariable[2][2], + sseVariable[3][0] + sseVariable[3][1] + sseVariable[3][2], + sseVariable[4][0] + sseVariable[4][1] + sseVariable[4][2]); + +#endif +} //lint !e715 // scale/transform not referenced - it's in the asm + +// ---------------------------------------------------------------------- + +void SseMath::skinPositionNormal_l2p(const Transform &transform, const Vector &sourcePosition, const Vector &sourceNormal, float scale, Vector &destPosition, Vector &destNormal) +{ + // NOTE: technically, my xmm register data contents comments are listing items in reverse order from how INTEL docs list them, left most val is really least significant value. + + __asm { + //-- Keep track of ebx. Client is crashing if I trash this. + push ebx + + //-- Load up matrix. + mov ebx, transform + + movaps xmm0, [ebx + 0] // xmm0 = a1 a2 a3 a4 + movaps xmm1, [ebx + 16] // xmm1 = b1 b2 b3 b4 + movaps xmm2, [ebx + 32] // xmm2 = c1 c2 c3 c4 + } + + //-- Prepare source position. + sseVariable[0][0] = sourcePosition.x; + sseVariable[0][1] = sourcePosition.y; + sseVariable[0][2] = sourcePosition.z; + sseVariable[0][3] = 1.0f; + + __asm { + //-- Load up the source vector. + mov ebx, offset sseVariable + + movaps xmm3, [ebx] // xmm3 = sx sy sz 1 + + //-- Copy source to workspaces. + movaps xmm4, xmm3 // xmm4 = sx sy sz 1 + movaps xmm5, xmm3 // xmm5 = sx sy sz 1 + + //-- Prepare the scale vector. + movss xmm6, scale // xmm6 = scale ? ? ? + shufps xmm6, xmm6, 0x00 // xmm6 = scale scale + movlhps xmm6, xmm6 // xmm6 = scale scale scale scale + + //-- Do the transform multiplies. + mulps xmm3, xmm0 // xmm3 = a1*sx a2*sy a3*sz a4 + mulps xmm4, xmm1 // xmm4 = b1*sx b2*sy b3*sz b4 + mulps xmm5, xmm2 // xmm5 = c1*sx c2*sy c3*sz c4 + + //-- Do the scale multiplies. + mulps xmm3, xmm6 // xmm3 = a1*sx*scale a2*sy*scale a3*sz*scale a4*scale + mulps xmm4, xmm6 // xmm4 = b1*sx*scale b2*sy*scale b3*sz*scale b4*scale + mulps xmm5, xmm6 // xmm5 = c1*sx*scale c2*sy*scale c3*sz*scale c4*scale + + //-- Save out data. + movaps [ebx + 32], xmm3 + movaps [ebx + 48], xmm4 + movaps [ebx + 64], xmm5 + } + + destPosition.x = sseVariable[2][0] + sseVariable[2][1] + sseVariable[2][2] + sseVariable[2][3]; + destPosition.y = sseVariable[3][0] + sseVariable[3][1] + sseVariable[3][2] + sseVariable[3][3]; + destPosition.z = sseVariable[4][0] + sseVariable[4][1] + sseVariable[4][2] + sseVariable[4][3]; + + //-- Prepare source normal. + sseVariable[0][0] = sourceNormal.x; + sseVariable[0][1] = sourceNormal.y; + sseVariable[0][2] = sourceNormal.z; + sseVariable[0][3] = 1.0f; + + __asm { + //-- Load up the source vector. + movaps xmm3, [ebx] // xmm3 = sx sy sz 1 + + //-- Copy source to workspaces. + movaps xmm4, xmm3 // xmm4 = sx sy sz 1 + movaps xmm5, xmm3 // xmm5 = sx sy sz 1 + + //-- Do the transform multiplies. + mulps xmm3, xmm0 // xmm3 = a1*sx a2*sy a3*sz a4 + mulps xmm4, xmm1 // xmm4 = b1*sx b2*sy b3*sz b4 + mulps xmm5, xmm2 // xmm5 = c1*sx c2*sy c3*sz c4 + + //-- Do the scale multiplies. + mulps xmm3, xmm6 // xmm3 = a1*sx*scale a2*sy*scale a3*sz*scale a4*scale + mulps xmm4, xmm6 // xmm4 = b1*sx*scale b2*sy*scale b3*sz*scale b4*scale + mulps xmm5, xmm6 // xmm5 = c1*sx*scale c2*sy*scale c3*sz*scale c4*scale + + //-- Save out data. + movaps [ebx + 32], xmm3 + movaps [ebx + 48], xmm4 + movaps [ebx + 64], xmm5 + + //-- Restore EBX + pop ebx + } + + destNormal.x = sseVariable[2][0] + sseVariable[2][1] + sseVariable[2][2]; + destNormal.y = sseVariable[3][0] + sseVariable[3][1] + sseVariable[3][2]; + destNormal.z = sseVariable[4][0] + sseVariable[4][1] + sseVariable[4][2]; +} //lint !e715 // scale/transform not referenced - it's in the asm + +// ---------------------------------------------------------------------- + +void SseMath::skinPositionNormalAdd_l2p(const Transform &transform, const Vector &sourcePosition, const Vector &sourceNormal, float scale, Vector &destPosition, Vector &destNormal) +{ + // NOTE: technically, my xmm register data contents comments are listing items in reverse order from how INTEL docs list them, left most val is really least significant value. + + __asm { + //-- Keep track of ebx. Client is crashing if I trash this. + push ebx + + //-- Load up matrix. + mov ebx, transform + + movaps xmm0, [ebx + 0] // xmm0 = a1 a2 a3 a4 + movaps xmm1, [ebx + 16] // xmm1 = b1 b2 b3 b4 + movaps xmm2, [ebx + 32] // xmm2 = c1 c2 c3 c4 + } + + //-- Prepare source position. + sseVariable[0][0] = sourcePosition.x; + sseVariable[0][1] = sourcePosition.y; + sseVariable[0][2] = sourcePosition.z; + sseVariable[0][3] = 1.0f; + + __asm { + //-- Load up the source vector. + mov ebx, offset sseVariable + + movaps xmm3, [ebx] // xmm3 = sx sy sz 1 + + //-- Copy source to workspaces. + movaps xmm4, xmm3 // xmm4 = sx sy sz 1 + movaps xmm5, xmm3 // xmm5 = sx sy sz 1 + + //-- Prepare the scale vector. + movss xmm6, scale // xmm6 = scale ? ? ? + shufps xmm6, xmm6, 0x00 // xmm6 = scale scale + movlhps xmm6, xmm6 // xmm6 = scale scale scale scale + + //-- Do the transform multiplies. + mulps xmm3, xmm0 // xmm3 = a1*sx a2*sy a3*sz a4 + mulps xmm4, xmm1 // xmm4 = b1*sx b2*sy b3*sz b4 + mulps xmm5, xmm2 // xmm5 = c1*sx c2*sy c3*sz c4 + + //-- Do the scale multiplies. + mulps xmm3, xmm6 // xmm3 = a1*sx*scale a2*sy*scale a3*sz*scale a4*scale + mulps xmm4, xmm6 // xmm4 = b1*sx*scale b2*sy*scale b3*sz*scale b4*scale + mulps xmm5, xmm6 // xmm5 = c1*sx*scale c2*sy*scale c3*sz*scale c4*scale + + //-- Save out data. + movaps [ebx + 32], xmm3 + movaps [ebx + 48], xmm4 + movaps [ebx + 64], xmm5 + } + + destPosition.x += sseVariable[2][0] + sseVariable[2][1] + sseVariable[2][2] + sseVariable[2][3]; + destPosition.y += sseVariable[3][0] + sseVariable[3][1] + sseVariable[3][2] + sseVariable[3][3]; + destPosition.z += sseVariable[4][0] + sseVariable[4][1] + sseVariable[4][2] + sseVariable[4][3]; + + //-- Prepare source normal. + sseVariable[0][0] = sourceNormal.x; + sseVariable[0][1] = sourceNormal.y; + sseVariable[0][2] = sourceNormal.z; + sseVariable[0][3] = 1.0f; + + __asm { + //-- Load up the source vector. + movaps xmm3, [ebx] // xmm3 = sx sy sz 1 + + //-- Copy source to workspaces. + movaps xmm4, xmm3 // xmm4 = sx sy sz 1 + movaps xmm5, xmm3 // xmm5 = sx sy sz 1 + + //-- Do the transform multiplies. + mulps xmm3, xmm0 // xmm3 = a1*sx a2*sy a3*sz a4 + mulps xmm4, xmm1 // xmm4 = b1*sx b2*sy b3*sz b4 + mulps xmm5, xmm2 // xmm5 = c1*sx c2*sy c3*sz c4 + + //-- Do the scale multiplies. + mulps xmm3, xmm6 // xmm3 = a1*sx*scale a2*sy*scale a3*sz*scale a4*scale + mulps xmm4, xmm6 // xmm4 = b1*sx*scale b2*sy*scale b3*sz*scale b4*scale + mulps xmm5, xmm6 // xmm5 = c1*sx*scale c2*sy*scale c3*sz*scale c4*scale + + //-- Save out data. + movaps [ebx + 32], xmm3 + movaps [ebx + 48], xmm4 + movaps [ebx + 64], xmm5 + + //-- Restore EBX + pop ebx + } + + destNormal.x += sseVariable[2][0] + sseVariable[2][1] + sseVariable[2][2]; + destNormal.y += sseVariable[3][0] + sseVariable[3][1] + sseVariable[3][2]; + destNormal.z += sseVariable[4][0] + sseVariable[4][1] + sseVariable[4][2]; +} //lint !e715 // scale/transform not referenced - it's in the asm + +// ====================================================================== diff --git a/engine/shared/library/sharedMath/src/win32/SseMath.h b/engine/shared/library/sharedMath/src/win32/SseMath.h new file mode 100644 index 00000000..fcbeaef2 --- /dev/null +++ b/engine/shared/library/sharedMath/src/win32/SseMath.h @@ -0,0 +1,58 @@ +// ====================================================================== +// +// SseMath.h +// Copyright 2002 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_SseMath_H +#define INCLUDED_SseMath_H + +// ====================================================================== + +class Transform; +class Vector; + +// ====================================================================== +#define MXCSR_FLUSH_TO_ZERO (1<<15) +#define MXCSR_PRECISION_MASK (1<<12) +#define MXCSR_UNDERFLOW_MASK (1<<11) +#define MXCSR_OVERFLOW_MASK (1<<10) +#define MXCSR_DIVIDE_BY_ZERO_MASK (1<< 9) +#define MXCSR_DENORMAL_MASK (1<< 8) + +class SseMath +{ +public: + + static bool canDoSseMath(); + + static Vector rotateTranslateScale_l2p(const Transform &transform, const Vector &vector, float scale); + static Vector rotateScale_l2p(const Transform &transform, const Vector &vector, float scale); + + static void skinPositionNormal_l2p(const Transform &transform, const Vector &position, const Vector &normal, float scale, Vector &destPosition, Vector &destNormal); + static void skinPositionNormalAdd_l2p(const Transform &transform, const Vector &position, const Vector &normal, float scale, Vector &destPosition, Vector &destNormal); + static void prefetch(void const * const sourceData, size_t const objectSize); +}; + +// ---------------------------------------------------------------------- + +inline void SseMath::prefetch(void const * const sourceData, size_t const objectSize) +{ +#if defined(_MSC_VER) + _asm + { + mov esi, sourceData + prefetchnta objectSize[esi] + } +#else + // rls - add linux version here. + UNREF(sourceData); + UNREF(objectSize); +#endif +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedRandom/CMakeLists.txt b/engine/shared/library/sharedRandom/CMakeLists.txt new file mode 100644 index 00000000..fd91ce31 --- /dev/null +++ b/engine/shared/library/sharedRandom/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 2.8) + +project(sharedRandom) + +if(WIN32) + add_definitions(/D_CRT_SECURE_NO_WARNINGS) +endif() + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/public) + +add_subdirectory(src) diff --git a/engine/shared/library/sharedRandom/include/public/sharedRandom/ConfigSharedRandom.h b/engine/shared/library/sharedRandom/include/public/sharedRandom/ConfigSharedRandom.h new file mode 100644 index 00000000..78dd6447 --- /dev/null +++ b/engine/shared/library/sharedRandom/include/public/sharedRandom/ConfigSharedRandom.h @@ -0,0 +1 @@ +#include "../../src/shared/ConfigSharedRandom.h" diff --git a/engine/shared/library/sharedRandom/include/public/sharedRandom/FastRandomGenerator.h b/engine/shared/library/sharedRandom/include/public/sharedRandom/FastRandomGenerator.h new file mode 100644 index 00000000..d7f32324 --- /dev/null +++ b/engine/shared/library/sharedRandom/include/public/sharedRandom/FastRandomGenerator.h @@ -0,0 +1 @@ +#include "../../src/shared/FastRandomGenerator.h" diff --git a/engine/shared/library/sharedRandom/include/public/sharedRandom/FirstSharedRandom.h b/engine/shared/library/sharedRandom/include/public/sharedRandom/FirstSharedRandom.h new file mode 100644 index 00000000..12a43e61 --- /dev/null +++ b/engine/shared/library/sharedRandom/include/public/sharedRandom/FirstSharedRandom.h @@ -0,0 +1 @@ +#include "../../src/shared/FirstSharedRandom.h" diff --git a/engine/shared/library/sharedRandom/include/public/sharedRandom/Random.h b/engine/shared/library/sharedRandom/include/public/sharedRandom/Random.h new file mode 100644 index 00000000..a0586cc4 --- /dev/null +++ b/engine/shared/library/sharedRandom/include/public/sharedRandom/Random.h @@ -0,0 +1 @@ +#include "../../src/shared/Random.h" diff --git a/engine/shared/library/sharedRandom/include/public/sharedRandom/RandomGenerator.h b/engine/shared/library/sharedRandom/include/public/sharedRandom/RandomGenerator.h new file mode 100644 index 00000000..964fe610 --- /dev/null +++ b/engine/shared/library/sharedRandom/include/public/sharedRandom/RandomGenerator.h @@ -0,0 +1 @@ +#include "../../src/shared/RandomGenerator.h" diff --git a/engine/shared/library/sharedRandom/include/public/sharedRandom/SetupSharedRandom.h b/engine/shared/library/sharedRandom/include/public/sharedRandom/SetupSharedRandom.h new file mode 100644 index 00000000..2235ee98 --- /dev/null +++ b/engine/shared/library/sharedRandom/include/public/sharedRandom/SetupSharedRandom.h @@ -0,0 +1 @@ +#include "../../src/shared/SetupSharedRandom.h" diff --git a/engine/shared/library/sharedRandom/src/CMakeLists.txt b/engine/shared/library/sharedRandom/src/CMakeLists.txt new file mode 100644 index 00000000..3be31afe --- /dev/null +++ b/engine/shared/library/sharedRandom/src/CMakeLists.txt @@ -0,0 +1,36 @@ + +set(SHARED_SOURCES + shared/ConfigSharedRandom.cpp + shared/ConfigSharedRandom.h + shared/FastRandomGenerator.h + shared/FirstSharedRandom.h + shared/Random.cpp + shared/Random.h + shared/RandomGenerator.cpp + shared/RandomGenerator.h + shared/SetupSharedRandom.cpp + shared/SetupSharedRandom.h +) + +if(WIN32) + set(PLATFORM_SOURCES + win32/FirstSharedRandom.cpp + ) + + 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/sharedFoundation/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundationTypes/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMemoryManager/include/public +) + +add_library(sharedRandom STATIC + ${SHARED_SOURCES} + ${PLATFORM_SOURCES} +) diff --git a/engine/shared/library/sharedRandom/src/shared/ConfigSharedRandom.cpp b/engine/shared/library/sharedRandom/src/shared/ConfigSharedRandom.cpp new file mode 100644 index 00000000..a2f937de --- /dev/null +++ b/engine/shared/library/sharedRandom/src/shared/ConfigSharedRandom.cpp @@ -0,0 +1,42 @@ +// ====================================================================== +// +// ConfigSharedRandom.cpp +// copyright 2004 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedRandom/FirstSharedRandom.h" +#include "sharedRandom/ConfigSharedRandom.h" + +#include "sharedFoundation/ConfigFile.h" + +// ====================================================================== + +#define KEY_BOOL(a,b) (ms_ ## a = ConfigFile::getKeyBool("SharedRandom", #a, (b))) + +// ====================================================================== + +namespace ConfigSharedRandomNamespace +{ + bool ms_sample; +} + +using namespace ConfigSharedRandomNamespace; + +// ====================================================================== + +void ConfigSharedRandom::install() +{ + KEY_BOOL(sample, false); +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedRandom::getSample() +{ + return ms_sample; +} + +// ====================================================================== + + diff --git a/engine/shared/library/sharedRandom/src/shared/ConfigSharedRandom.h b/engine/shared/library/sharedRandom/src/shared/ConfigSharedRandom.h new file mode 100644 index 00000000..6b930392 --- /dev/null +++ b/engine/shared/library/sharedRandom/src/shared/ConfigSharedRandom.h @@ -0,0 +1,24 @@ +// ====================================================================== +// +// ConfigSharedRandom.h +// Copyright 2004, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_ConfigSharedRandom_H +#define INCLUDED_ConfigSharedRandom_H + +// ====================================================================== + +class ConfigSharedRandom +{ +public: + + static void install(); + static bool getSample(); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedRandom/src/shared/FastRandomGenerator.h b/engine/shared/library/sharedRandom/src/shared/FastRandomGenerator.h new file mode 100644 index 00000000..7896ca5a --- /dev/null +++ b/engine/shared/library/sharedRandom/src/shared/FastRandomGenerator.h @@ -0,0 +1,71 @@ +// ====================================================================== +// +// RandomGenerator.h +// By Ben Earhart +// +// copyright 2005 Bootprint Entertainment +// +// ====================================================================== + +#ifndef _FAST_RANDOM_GENERATOR_H_ +#define _FAST_RANDOM_GENERATOR_H_ + +// ====================================================================== + +class FastRandomGenerator +{ +public: + FastRandomGenerator() { m_I=ZERO_ALT; } + FastRandomGenerator(long s) { setSeed(s); } + + void setSeed(long s) + { + const long ps = s&0x7fffffff; + m_I = (ps==0) ? ZERO_ALT : ps; + } + + // return a random number r where 0<=r<1 + float randomFloat() + { + long f = (_rand()>>8)|IEEE_FLOAT_BITS; + return (*(float *)(void *)&f)-1.0f; + } + float randomFloat(float range) { return randomFloat()*range; } + float randomFloat(float low, float high) { return randomFloat()*(high-low) + low; } + + int random() { return _rand(); } + int random(int range) { return random()%range; } + int random(int low, int high) { return (random()%(high-low)) + low; } + +protected: + + enum { IEEE_FLOAT_BITS=0x3f800000 }; + + enum { + IA = 16807, + IM = 2147483647, + IQ = 127773, + IR = 2836, + ZERO_ALT = 123459876 + }; + + long _rand() + { + long k; + k=m_I/IQ; + m_I=IA*(m_I-k*IQ)-IR*k; + if (m_I<0) m_I += IM; + k = m_I; + return k; + } + + long _randMax() { return IM-1; } + + long m_I; +}; + +// ====================================================================== + +#endif + + diff --git a/engine/shared/library/sharedRandom/src/shared/FirstSharedRandom.h b/engine/shared/library/sharedRandom/src/shared/FirstSharedRandom.h new file mode 100644 index 00000000..4f4b7730 --- /dev/null +++ b/engine/shared/library/sharedRandom/src/shared/FirstSharedRandom.h @@ -0,0 +1,19 @@ +// ====================================================================== +// +// FirstRandom.h +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_FirstRandom_H +#define INCLUDED_FirstRandom_H + +// ====================================================================== + +#include "sharedDebug/FirstSharedDebug.h" +#include "sharedFoundation/FirstSharedFoundation.h" + +// ====================================================================== + +#endif + diff --git a/engine/shared/library/sharedRandom/src/shared/Random.cpp b/engine/shared/library/sharedRandom/src/shared/Random.cpp new file mode 100644 index 00000000..42ddcc0b --- /dev/null +++ b/engine/shared/library/sharedRandom/src/shared/Random.cpp @@ -0,0 +1,50 @@ +// ====================================================================== +// +// Random.cpp +// By Eric Sebesta +// +// copyright 1999 Bootprint Entertainment +// +// ====================================================================== + +#include "sharedRandom/FirstSharedRandom.h" +#include "sharedRandom/Random.h" + +#include "sharedRandom/RandomGenerator.h" +#include "sharedFoundation/ExitChain.h" + +// ====================================================================== + +RandomGenerator* Random::rand; +bool Random::installed; + +// ====================================================================== +// Static function install this module +// +// Remarks: +// +// None. + +void Random::install(uint32 newSeed) +{ + DEBUG_FATAL(installed, ("already installed")); + installed = true; + ExitChain::add(Random::remove, "Random::remove", 0, false); + rand = new RandomGenerator(newSeed); +} + +// ---------------------------------------------------------------------- +/** + * Static function to remove this module. + * + * None. + */ + +void Random::remove(void) +{ + DEBUG_FATAL(!installed, ("not installed")); + installed = false; + delete rand; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedRandom/src/shared/Random.h b/engine/shared/library/sharedRandom/src/shared/Random.h new file mode 100644 index 00000000..232e0ae4 --- /dev/null +++ b/engine/shared/library/sharedRandom/src/shared/Random.h @@ -0,0 +1,190 @@ +// ====================================================================== +// +// Random.h +// By Eric Sebesta +// +// copyright 1999 Bootprint Entertainment +// +// ====================================================================== + +#ifndef _RANDOM_H_ +#define _RANDOM_H_ + +#include "sharedRandom/RandomGenerator.h" + +// ====================================================================== +// Provides an interface to a global random number generator +// +// Remarks: +// +// It must have install() called before use. It creates a global random number +// generator. To create local random number generators, use RandomGenerator. +// The RandomGenerator class depends on this class to generate the seeds for it. + +class Random +{ +private: + //private static data members + static RandomGenerator* rand; + static bool installed; + +public: + //public static member functions + static void install (uint32 newSeed); + static void remove (void); + + static real randomReal (void); + static real randomReal (real range); + static real randomReal (real low, real high); + static int32 random (void); + static int32 random (int32 range); + static int32 random (int32 low, int32 high); + + static int32 getSeed (void); + static void setSeed (uint32 newSeed); + + static bool isInstalled (void); + +private: + // disable: default constructor, copy constructor, assignment operator + Random (void); + Random (const Random&); + Random &operator =(const Random&); +}; + +// ---------------------------------------------------------------------- +/** + * Static function to get a real random number between 0 and 1. + * + * None. + * + * @return A real random number between (and including) 0 and max(real) + */ + +inline real Random::randomReal (void) +{ + DEBUG_FATAL(!installed, ("not installed")); + return rand->randomReal(); +} + +// ---------------------------------------------------------------------- +/** + * Static function to get a int32 random number between 0 and max(int32). + * + * None. + * + * @return A int32 random number between (and including) 0 and max(int32) + */ + +inline int32 Random::random (void) +{ + DEBUG_FATAL(!installed, ("not installed")); + return rand->random(); +} + +// ---------------------------------------------------------------------- +/** + * Static function to get a real random number between low and high. + * + * None. + * + * @return A real random number between (and including) low and high. + */ + +inline real Random::randomReal (real low, real high) +{ + DEBUG_FATAL(!installed, ("not installed")); + return rand->randomReal(low, high); +} + +// ---------------------------------------------------------------------- +/** + * Static function to get a int32 random number between low and high. + * + * None. + * + * @return A int32 random number between (and including) low and high. + */ + +inline int32 Random::random (int32 low, int32 high) +{ + DEBUG_FATAL(!installed, ("not installed")); + return rand->random(low, high); +} + +// ---------------------------------------------------------------------- +/** + * Static function to get a int32 random number between 0 and range. + * + * None. + * + * @return A int32 random number between (and including) 0 and range. + */ + +inline int32 Random::random (int32 range) +{ + DEBUG_FATAL(!installed, ("not installed")); + DEBUG_FATAL(range < 0, ("range < 0, use random(-range, 0)")); + return rand->random(0, range); +} + +// ---------------------------------------------------------------------- +/** + * Static function to get a real random number between 0 and range. + * + * None. + * + * @return A real random number between (and including) 0 and range. + */ + +inline real Random::randomReal (real range) +{ + DEBUG_FATAL(!installed, ("not installed")); + DEBUG_FATAL(range < 0, ("range < 0, use randomReal(-range, 0)")); + return rand->randomReal (CONST_REAL(0), range); +} + +// ---------------------------------------------------------------------- +/** + * Static function to get the current global seed. + * + * None. + * + * @return The current seed. + */ + +inline int32 Random::getSeed (void) +{ + DEBUG_FATAL(!installed, ("not installed")); + return rand->getSeed(); +} + +// ---------------------------------------------------------------------- +/** + * Static function to set the global seed. + * + * Can be used midgame to change the seed. Note that if seeded to a previously used value, repetition may result. + */ + +inline void Random::setSeed (uint32 newSeed) +{ + DEBUG_FATAL(!installed, ("not installed")); + rand->setSeed(newSeed); +} + +// ---------------------------------------------------------------------- +/** + * Static function determine if this module is installed. + * + * None + */ + +inline bool Random::isInstalled () +{ + DEBUG_FATAL(!installed, ("not installed")); + return installed; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedRandom/src/shared/RandomGenerator.cpp b/engine/shared/library/sharedRandom/src/shared/RandomGenerator.cpp new file mode 100644 index 00000000..ca00e4af --- /dev/null +++ b/engine/shared/library/sharedRandom/src/shared/RandomGenerator.cpp @@ -0,0 +1,72 @@ +// ====================================================================== +// +// RandomGenerator.h +// By Eric Sebesta +// +// copyright 1999 Bootprint Entertainment +// +// ====================================================================== + +#include "sharedRandom/FirstSharedRandom.h" +#include "sharedRandom/RandomGenerator.h" + +#include "sharedRandom/Random.h" + +// ====================================================================== + +const real RandomGenerator::AM = CONST_REAL(1.0/IM); +const real RandomGenerator::NDIV = CONST_REAL(1+(IM-1)/static_cast(NTAB)); +const real RandomGenerator::EPS = CONST_REAL(1.2e-7); +const real RandomGenerator::RNMX = CONST_REAL(1.0-EPS); + +// ====================================================================== +// Construct a RandomGenerator +// +// Remarks: +// +// Sets seed based on the global Random::random() call (i.e different for every RandomGenerator). + +RandomGenerator::RandomGenerator (void) +: idnum (-Random::random()+1), //+1 so that our seed is different from the global one + iy (0) +{ + memset(iv, 0, sizeof(iv)); +} + +// ---------------------------------------------------------------------- + +int32 RandomGenerator::randomNumber (void) +{ +// This random algorithm comes from ran1() in Numerical Recipes in C, p. 280 + + int32 j; + int32 k; + + if(idnum <= 0 || !iy) + { + if(-(idnum) < 1) //initialize + idnum = 1; + else + idnum = -(idnum); + for (j = NTAB+7; j >= 0; --j) //use idnum as the "seed value" + { + k = (idnum)/IQ; + idnum = IA * (idnum-k *IQ) - IR*k; + if (idnum < 0) + idnum += IM; + if (j < NTAB) + iv[j] = idnum; + } + iy=iv[0]; + } + k = (idnum) / IQ; //start here when not initializing + idnum = IA*(idnum-k*IQ)-IR*k; //generate random number (Schrage's Method) + if (idnum < 0) + idnum += IM; + j = static_cast(iy/NDIV); //put in range 0...NTAB-1 + iy = iv[j]; //iy is our new random number + iv[j] = idnum; + return iy; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedRandom/src/shared/RandomGenerator.h b/engine/shared/library/sharedRandom/src/shared/RandomGenerator.h new file mode 100644 index 00000000..9a2eef9d --- /dev/null +++ b/engine/shared/library/sharedRandom/src/shared/RandomGenerator.h @@ -0,0 +1,217 @@ +// ====================================================================== +// +// RandomGenerator.h +// By Eric Sebesta +// +// copyright 1999 Bootprint Entertainment +// +// ====================================================================== + +#ifndef _RANDOM_GENERATOR_H_ +#define _RANDOM_GENERATOR_H_ + +// ====================================================================== +// A class to generate random numbers +// +// Remarks: +// +// This class generates 31-bit random numbers returned as either 32-bit +// integers or as reals. Note that Random::install() MUST be called prior +// to creation of RandomGenerator classes. Random represents a +// global random number generator, and is used to generate seeds for all +// RandomGenerator classes. Failing to call Random::install() will Fatal in +// debug builds and have undefined behavior in release builds. This class +// uses a random number generation algorithm found in Numerical Recipes in C, +// on p. 280. + +class RandomGenerator +{ + +private: + //private member functions + int32 randomNumber (void); + +private: + + enum + { + IM = 2147483647, + NTAB = 322, + IA = 16807, + IQ = 127773, + IR = 2836 + }; + + static const real AM; + static const real NDIV; + static const real EPS; + static const real RNMX; + +private: + + //private member variables + int32 idnum; + int32 iy; + int32 iv[NTAB]; + +public: + //constructors and destructors + RandomGenerator (void); + explicit RandomGenerator (uint32 newSeed); + ~RandomGenerator (void); + + //public member functions + real randomReal (void); + real randomReal (real range); + real randomReal (real low, real high); + int32 random (void); + int32 random (int32 range); + int32 random (int32 low, int32 high); + + int32 getSeed (void); + void setSeed (uint32 newSeed); +}; + +// ====================================================================== +// Construct a RandomGenerator +// +// Remarks: +// +// Uses the user-supplied seed. + +inline RandomGenerator::RandomGenerator (uint32 newSeed) +: idnum (-static_cast(newSeed)), + iy (0) +{ + memset(iv, 0, sizeof(iv)); +} + +// ====================================================================== +// Destruct a RandomGenerator +// +// Remarks: +// +// None. + +inline RandomGenerator::~RandomGenerator (void) +{ +} + +// ---------------------------------------------------------------------- +/** + * Get a real random number between 0 and max(real). + * + * None. + * + * @return A real random number between (and including) 0 and 1 + */ + +inline real RandomGenerator::randomReal (void) +{ + return static_cast( randomNumber () ) / static_cast( IM ); +} + +// ---------------------------------------------------------------------- +/** + * Get a int32 random number between 0 and max(int32). + * + * None. + * + * @return A int32 random number between (and including) 0 and max(int32) + */ + +inline int32 RandomGenerator::random (void) +{ + return randomNumber (); +} + +// ---------------------------------------------------------------------- +/** + * Get a real random number between low and high. + * + * None. + * + * @return A real random number between (and including) low and high. + */ + +inline real RandomGenerator::randomReal (real low, real high) +{ + DEBUG_FATAL(low > high, ("low > high")); + return static_cast(randomReal() * (high - low) + low); +} + +// ---------------------------------------------------------------------- +/** + * Get a int32 random number between low and high. + * + * None. + * + * @return A int32 random number between (and including) low and high. + */ + +inline int32 RandomGenerator::random (int32 low, int32 high) +{ + DEBUG_FATAL(low > high, ("low > high")); + return ( random () % ( high - low + 1 ) + low ); +} + +// ---------------------------------------------------------------------- +/** + * Get a int32 random number between 0 and range. + * + * None. + * + * @return A int32 random number between (and including) 0 and range. + */ + +inline int32 RandomGenerator::random (int32 range) +{ + DEBUG_FATAL(range < 0, ("range < 0, use random(-range, 0)")); + return random ( 0, range ); +} + +// ---------------------------------------------------------------------- +/** + * Get a real random number between 0 and range. + * + * None. + * + * @return A real random number between (and including) 0 and range. + */ + +inline real RandomGenerator::randomReal (real range) +{ + DEBUG_FATAL(range < 0, ("range < 0, use randomReal(-range, 0)")); + return randomReal ( CONST_REAL(0), range ); +} + +// ---------------------------------------------------------------------- +/** + * Get the current seed. + * + * None. + * + * @return The current seed. + */ + +inline int32 RandomGenerator::getSeed (void) +{ + return iy; +} + +// ---------------------------------------------------------------------- +/** + * Set the seed. + * + * Can be used midgame to change the seed. Note that if seeded to a previously used value, repetition may result. + */ + +inline void RandomGenerator::setSeed (uint32 newSeed) +{ + iy = 0; + idnum = -(static_cast(newSeed)); //since a negative value will cause the ran1() as used in randomNumber to "reseed" +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedRandom/src/shared/SetupSharedRandom.cpp b/engine/shared/library/sharedRandom/src/shared/SetupSharedRandom.cpp new file mode 100644 index 00000000..3ba595c6 --- /dev/null +++ b/engine/shared/library/sharedRandom/src/shared/SetupSharedRandom.cpp @@ -0,0 +1,25 @@ +// ====================================================================== +// +// SetupSharedRandom.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedRandom/FirstSharedRandom.h" +#include "sharedRandom/SetupSharedRandom.h" + +#include "sharedDebug/InstallTimer.h" +#include "sharedRandom/ConfigSharedRandom.h" +#include "sharedRandom/Random.h" + +// ====================================================================== + +void SetupSharedRandom::install(uint32 seed) +{ + InstallTimer const installTimer("SetupSharedRandom::install"); + + ConfigSharedRandom::install(); + Random::install(seed); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedRandom/src/shared/SetupSharedRandom.h b/engine/shared/library/sharedRandom/src/shared/SetupSharedRandom.h new file mode 100644 index 00000000..65d8370a --- /dev/null +++ b/engine/shared/library/sharedRandom/src/shared/SetupSharedRandom.h @@ -0,0 +1,27 @@ +// ====================================================================== +// +// SetupSharedRandom.h +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_SetupSharedRandom_H +#define INCLUDED_SetupSharedRandom_H + +// ====================================================================== + +class SetupSharedRandom +{ +public: + + static void install(uint32 seed); + +private: + SetupSharedRandom(); + SetupSharedRandom(const SetupSharedRandom &); + SetupSharedRandom &operator =(const SetupSharedRandom &); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedRandom/src/win32/FirstSharedRandom.cpp b/engine/shared/library/sharedRandom/src/win32/FirstSharedRandom.cpp new file mode 100644 index 00000000..1ce55673 --- /dev/null +++ b/engine/shared/library/sharedRandom/src/win32/FirstSharedRandom.cpp @@ -0,0 +1,8 @@ +// ====================================================================== +// +// FirstRandom.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedRandom/FirstSharedRandom.h"