Archival snapshot of the Virtual World Entertainment Tesla cockpit software, 1994-1996: MUNGA engine and L4 pod layer source (Borland C++ 5.0), BT/RP game code, and game content (models, audio, maps, gauges, Division renderer data). Includes third-party libraries: Division dVS/DPL graphics, HMI SOS audio, WATTCP networking. Files are preserved byte-for-byte (.gitattributes disables all line-ending conversion). README.md documents the layout, target hardware, and toolchain. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1440 lines
39 KiB
C++
1440 lines
39 KiB
C++
//===========================================================================//
|
|
// File: boxsolid.cpp //
|
|
// Project: MUNGA Brick: Spatializer Library //
|
|
// Contents: Implementation details of bounding-box collision subtypes //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 01/11/95 JMA Initial port back to C++ //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1993-1996, Virtual World Entertainment, Inc. //
|
|
// All Rights reserved worldwide //
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#include <munga.hpp>
|
|
#pragma hdrstop
|
|
|
|
#if !defined(BOXSOLID_HPP)
|
|
# include <boxsolid.hpp>
|
|
#endif
|
|
|
|
#if !defined(FILEUTIL_HPP)
|
|
# include <fileutil.hpp>
|
|
#endif
|
|
|
|
#if !defined(ORIGIN_HPP)
|
|
# include <origin.hpp>
|
|
#endif
|
|
|
|
#if !defined(LINMTRX_HPP)
|
|
# include <linmtrx.hpp>
|
|
#endif
|
|
|
|
#if !defined(LINE_HPP)
|
|
# include <line.hpp>
|
|
#endif
|
|
|
|
#if !defined(NOTATION_HPP)
|
|
# include <notation.hpp>
|
|
#endif
|
|
|
|
//#############################################################################
|
|
//############################## BoxedSolid #############################
|
|
//#############################################################################
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
BoxedSolid::BoxedSolid(
|
|
const ExtentBox &extents,
|
|
BoxedSolid::Type type,
|
|
BoxedSolid::Material material,
|
|
Simulation *owner,
|
|
BoxedSolid *next_solid
|
|
):
|
|
TaggedBoundingBox(extents, owner)
|
|
{
|
|
|
|
Check_Pointer(this);
|
|
solidType = type;
|
|
materialType = material;
|
|
nextSolid = next_solid;
|
|
if (nextSolid)
|
|
{
|
|
Check(nextSolid);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
BoxedSolid::BoxedSolid(
|
|
const ExtentBox &extents,
|
|
Material material,
|
|
Simulation *owner,
|
|
BoxedSolid *next_solid
|
|
):
|
|
TaggedBoundingBox(extents, owner)
|
|
{
|
|
Check_Pointer(this);
|
|
solidType = BlockType;
|
|
materialType = material;
|
|
nextSolid = next_solid;
|
|
if (nextSolid)
|
|
{
|
|
Check(nextSolid);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
BoxedSolid::~BoxedSolid()
|
|
{
|
|
Check_Pointer(this);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
BoxedSolid *
|
|
BoxedSolid::MakeBoxedSolid(
|
|
BoxedSolidResource *boxed_solid_resource,
|
|
Simulation *owner,
|
|
BoxedSolid *next_solid
|
|
)
|
|
{
|
|
|
|
BoxedSolid *boxed_solid;
|
|
|
|
switch(boxed_solid_resource->solidType)
|
|
{
|
|
case BoxedSolid::BlockType:
|
|
boxed_solid =
|
|
new BoxedSolid(
|
|
boxed_solid_resource->solidExtents,
|
|
boxed_solid_resource->materialType,
|
|
owner,
|
|
next_solid
|
|
);
|
|
break;
|
|
case BoxedSolid::SphereType:
|
|
boxed_solid =
|
|
new BoxedSphere(
|
|
boxed_solid_resource->solidExtents,
|
|
boxed_solid_resource->materialType,
|
|
owner,
|
|
next_solid
|
|
);
|
|
break;
|
|
case BoxedSolid::ConeType:
|
|
boxed_solid =
|
|
new BoxedCone(
|
|
boxed_solid_resource->solidExtents,
|
|
boxed_solid_resource->materialType,
|
|
owner,
|
|
next_solid
|
|
);
|
|
break;
|
|
case BoxedSolid::ReducibleBlockType:
|
|
boxed_solid =
|
|
new BoxedReducibleBlock(
|
|
boxed_solid_resource->solidExtents,
|
|
boxed_solid_resource->materialType,
|
|
owner,
|
|
next_solid
|
|
);
|
|
break;
|
|
case BoxedSolid::RampFacingNegativeZType:
|
|
boxed_solid =
|
|
new BoxedRampFacingNegativeZ(
|
|
boxed_solid_resource->solidExtents,
|
|
boxed_solid_resource->materialType,
|
|
owner,
|
|
next_solid
|
|
);
|
|
break;
|
|
case BoxedSolid::RampFacingNegativeXType:
|
|
boxed_solid =
|
|
new BoxedRampFacingNegativeX(
|
|
boxed_solid_resource->solidExtents,
|
|
boxed_solid_resource->materialType,
|
|
owner,
|
|
next_solid
|
|
);
|
|
break;
|
|
case BoxedSolid::RampFacingPositiveZType:
|
|
boxed_solid =
|
|
new BoxedRampFacingPositiveZ(
|
|
boxed_solid_resource->solidExtents,
|
|
boxed_solid_resource->materialType,
|
|
owner,
|
|
next_solid
|
|
);
|
|
break;
|
|
case BoxedSolid::RampFacingPositiveXType:
|
|
boxed_solid =
|
|
new BoxedRampFacingPositiveX(
|
|
boxed_solid_resource->solidExtents,
|
|
boxed_solid_resource->materialType,
|
|
owner,
|
|
next_solid
|
|
);
|
|
break;
|
|
case BoxedSolid::InvertedRampFacingNegativeZType:
|
|
boxed_solid =
|
|
new BoxedInvertedRampFacingNegativeZ(
|
|
boxed_solid_resource->solidExtents,
|
|
boxed_solid_resource->materialType,
|
|
owner,
|
|
next_solid
|
|
);
|
|
break;
|
|
case BoxedSolid::InvertedRampFacingNegativeXType:
|
|
boxed_solid =
|
|
new BoxedInvertedRampFacingNegativeX(
|
|
boxed_solid_resource->solidExtents,
|
|
boxed_solid_resource->materialType,
|
|
owner,
|
|
next_solid
|
|
);
|
|
break;
|
|
case BoxedSolid::InvertedRampFacingPositiveZType:
|
|
boxed_solid =
|
|
new BoxedInvertedRampFacingPositiveZ(
|
|
boxed_solid_resource->solidExtents,
|
|
boxed_solid_resource->materialType,
|
|
owner,
|
|
next_solid
|
|
);
|
|
break;
|
|
case BoxedSolid::InvertedRampFacingPositiveXType:
|
|
boxed_solid =
|
|
new BoxedInvertedRampFacingPositiveX(
|
|
boxed_solid_resource->solidExtents,
|
|
boxed_solid_resource->materialType,
|
|
owner,
|
|
next_solid
|
|
);
|
|
break;
|
|
case BoxedSolid::WedgeFacingNegativeZAndPositiveXType:
|
|
boxed_solid =
|
|
new BoxedWedgeFacingNegativeZAndPositiveX(
|
|
boxed_solid_resource->solidExtents,
|
|
boxed_solid_resource->materialType,
|
|
owner,
|
|
next_solid
|
|
);
|
|
break;
|
|
case BoxedSolid::WedgeFacingNegativeZAndNegativeXType:
|
|
boxed_solid =
|
|
new BoxedWedgeFacingNegativeZAndNegativeX(
|
|
boxed_solid_resource->solidExtents,
|
|
boxed_solid_resource->materialType,
|
|
owner,
|
|
next_solid
|
|
);
|
|
break;
|
|
case BoxedSolid::WedgeFacingPositiveZAndNegativeXType:
|
|
boxed_solid =
|
|
new BoxedWedgeFacingPositiveZAndNegativeX(
|
|
boxed_solid_resource->solidExtents,
|
|
boxed_solid_resource->materialType,
|
|
owner,
|
|
next_solid
|
|
);
|
|
break;
|
|
case BoxedSolid::WedgeFacingPositiveZAndPositiveXType:
|
|
boxed_solid =
|
|
new BoxedWedgeFacingPositiveZAndPositiveX(
|
|
boxed_solid_resource->solidExtents,
|
|
boxed_solid_resource->materialType,
|
|
owner,
|
|
next_solid
|
|
);
|
|
break;
|
|
case BoxedSolid::XAxisCylinderType:
|
|
boxed_solid =
|
|
new BoxedXAxisCylinder(
|
|
boxed_solid_resource->solidExtents,
|
|
boxed_solid_resource->materialType,
|
|
owner,
|
|
next_solid
|
|
);
|
|
break;
|
|
case BoxedSolid::YAxisCylinderType:
|
|
boxed_solid =
|
|
new BoxedYAxisCylinder(
|
|
boxed_solid_resource->solidExtents,
|
|
boxed_solid_resource->materialType,
|
|
owner,
|
|
next_solid
|
|
);
|
|
break;
|
|
case BoxedSolid::ZAxisCylinderType:
|
|
boxed_solid =
|
|
new BoxedZAxisCylinder(
|
|
boxed_solid_resource->solidExtents,
|
|
boxed_solid_resource->materialType,
|
|
owner,
|
|
next_solid
|
|
);
|
|
break;
|
|
#if 0
|
|
case BoxedSolid::RightHandedTileType:
|
|
{
|
|
TileResource *terrain =
|
|
(TileResource*)boxed_solid_resource;
|
|
boxed_solid =
|
|
new RightHandedTile(
|
|
boxed_solid_resource->solidExtents,
|
|
boxed_solid_resource->materialType,
|
|
owner,
|
|
next_solid,
|
|
terrain->cornerHeight
|
|
);
|
|
}
|
|
break;
|
|
case BoxedSolid::LeftHandedTileType:
|
|
{
|
|
TileResource *terrain =
|
|
(TileResource*)boxed_solid_resource;
|
|
boxed_solid =
|
|
new LeftHandedTile(
|
|
boxed_solid_resource->solidExtents,
|
|
boxed_solid_resource->materialType,
|
|
owner,
|
|
next_solid,
|
|
terrain->cornerHeight
|
|
);
|
|
}
|
|
break;
|
|
#endif
|
|
#if defined(LAB_ONLY)
|
|
default:
|
|
Dump(boxed_solid_resource->solidType);
|
|
Fail("Bad box type!");
|
|
#endif
|
|
}
|
|
|
|
Check(boxed_solid);
|
|
return boxed_solid;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Logical
|
|
#if DEBUG_LEVEL>0
|
|
BoxedSolid::VerifyCollision(BoxedSolidCollision &collision)
|
|
#else
|
|
BoxedSolid::VerifyCollision(BoxedSolidCollision &)
|
|
#endif
|
|
{
|
|
Check(this);
|
|
Check(&collision);
|
|
|
|
Verify(minX <= collision.collisionSlice.minX);
|
|
Verify(maxX >= collision.collisionSlice.maxX);
|
|
Verify(minY <= collision.collisionSlice.minY);
|
|
Verify(maxY >= collision.collisionSlice.maxY);
|
|
Verify(minZ <= collision.collisionSlice.minZ);
|
|
Verify(maxZ >= collision.collisionSlice.maxZ);
|
|
|
|
return True;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Logical
|
|
BoxedSolid::ProcessCollision(
|
|
BoxedSolidCollision &,
|
|
const Vector3D &,
|
|
BoxedSolidCollisionList *,
|
|
Normal *,
|
|
Scalar *
|
|
)
|
|
{
|
|
Fail("Unsupported mover collision type!\n");
|
|
return False;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
Logical
|
|
BoxedSolid::TestInstance() const
|
|
{
|
|
return solidType == BlockType;
|
|
}
|
|
|
|
//#############################################################################
|
|
//########################## BoxedSolidResource #########################
|
|
//#############################################################################
|
|
|
|
static const BoxedSolid::Type
|
|
Left_90[BoxedSolid::SolidTypeCount]=
|
|
{
|
|
BoxedSolid::BlockType, BoxedSolid::SphereType,
|
|
BoxedSolid::ConeType, BoxedSolid::ReducibleBlockType,
|
|
|
|
BoxedSolid::RampFacingNegativeXType,
|
|
BoxedSolid::RampFacingPositiveZType,
|
|
BoxedSolid::RampFacingPositiveXType,
|
|
BoxedSolid::RampFacingNegativeZType,
|
|
|
|
BoxedSolid::InvertedRampFacingNegativeXType,
|
|
BoxedSolid::InvertedRampFacingPositiveZType,
|
|
BoxedSolid::InvertedRampFacingPositiveXType,
|
|
BoxedSolid::InvertedRampFacingNegativeZType,
|
|
|
|
BoxedSolid::WedgeFacingNegativeZAndNegativeXType,
|
|
BoxedSolid::WedgeFacingPositiveZAndNegativeXType,
|
|
BoxedSolid::WedgeFacingPositiveZAndPositiveXType,
|
|
BoxedSolid::WedgeFacingNegativeZAndPositiveXType,
|
|
|
|
BoxedSolid::ZAxisCylinderType,
|
|
BoxedSolid::YAxisCylinderType,
|
|
BoxedSolid::XAxisCylinderType,
|
|
|
|
BoxedSolid::LeftHandedTileType,
|
|
BoxedSolid::RightHandedTileType
|
|
};
|
|
|
|
static const BoxedSolid::Type
|
|
Left_180[BoxedSolid::SolidTypeCount]=
|
|
{
|
|
BoxedSolid::BlockType, BoxedSolid::SphereType,
|
|
BoxedSolid::ConeType, BoxedSolid::ReducibleBlockType,
|
|
|
|
BoxedSolid::RampFacingPositiveZType,
|
|
BoxedSolid::RampFacingPositiveXType,
|
|
BoxedSolid::RampFacingNegativeZType,
|
|
BoxedSolid::RampFacingNegativeXType,
|
|
|
|
BoxedSolid::InvertedRampFacingPositiveZType,
|
|
BoxedSolid::InvertedRampFacingPositiveXType,
|
|
BoxedSolid::InvertedRampFacingNegativeZType,
|
|
BoxedSolid::InvertedRampFacingNegativeXType,
|
|
|
|
BoxedSolid::WedgeFacingPositiveZAndNegativeXType,
|
|
BoxedSolid::WedgeFacingPositiveZAndPositiveXType,
|
|
BoxedSolid::WedgeFacingNegativeZAndPositiveXType,
|
|
BoxedSolid::WedgeFacingNegativeZAndNegativeXType,
|
|
|
|
BoxedSolid::XAxisCylinderType,
|
|
BoxedSolid::YAxisCylinderType,
|
|
BoxedSolid::ZAxisCylinderType,
|
|
|
|
BoxedSolid::RightHandedTileType,
|
|
BoxedSolid::LeftHandedTileType
|
|
};
|
|
|
|
static const BoxedSolid::Type
|
|
Left_270[BoxedSolid::SolidTypeCount]=
|
|
{
|
|
BoxedSolid::BlockType, BoxedSolid::SphereType,
|
|
BoxedSolid::ConeType, BoxedSolid::ReducibleBlockType,
|
|
|
|
BoxedSolid::RampFacingPositiveXType,
|
|
BoxedSolid::RampFacingNegativeZType,
|
|
BoxedSolid::RampFacingNegativeXType,
|
|
BoxedSolid::RampFacingPositiveZType,
|
|
|
|
BoxedSolid::InvertedRampFacingPositiveXType,
|
|
BoxedSolid::InvertedRampFacingNegativeZType,
|
|
BoxedSolid::InvertedRampFacingNegativeXType,
|
|
BoxedSolid::InvertedRampFacingPositiveZType,
|
|
|
|
BoxedSolid::WedgeFacingPositiveZAndPositiveXType,
|
|
BoxedSolid::WedgeFacingNegativeZAndPositiveXType,
|
|
BoxedSolid::WedgeFacingNegativeZAndNegativeXType,
|
|
BoxedSolid::WedgeFacingPositiveZAndNegativeXType,
|
|
|
|
BoxedSolid::ZAxisCylinderType,
|
|
BoxedSolid::YAxisCylinderType,
|
|
BoxedSolid::XAxisCylinderType,
|
|
|
|
BoxedSolid::LeftHandedTileType,
|
|
BoxedSolid::RightHandedTileType
|
|
};
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
BoxedSolidResource::Instance(
|
|
const BoxedSolidResource &source,
|
|
const Origin& origin
|
|
)
|
|
{
|
|
materialType = source.materialType;
|
|
|
|
//
|
|
//-------------------
|
|
// Handle no rotation
|
|
//-------------------
|
|
//
|
|
if (Close_Enough(origin.angularPosition.w, 1.0f))
|
|
{
|
|
solidType = source.solidType;
|
|
solidExtents = source.solidExtents;
|
|
sliceExtents = source.sliceExtents;
|
|
}
|
|
|
|
//
|
|
//-------------------------------
|
|
// Test for a 180 degree rotation
|
|
//-------------------------------
|
|
//
|
|
else if (Close_Enough(fabs(origin.angularPosition.y), 1.0f))
|
|
{
|
|
solidType = Left_180[source.solidType];
|
|
solidExtents.minX = -source.solidExtents.maxX;
|
|
solidExtents.maxX = -source.solidExtents.minX;
|
|
solidExtents.minY = source.solidExtents.minY;
|
|
solidExtents.maxY = source.solidExtents.maxY;
|
|
solidExtents.minZ = -source.solidExtents.maxZ;
|
|
solidExtents.maxZ = -source.solidExtents.minZ;
|
|
sliceExtents.minX = -source.sliceExtents.maxX;
|
|
sliceExtents.maxX = -source.sliceExtents.minX;
|
|
sliceExtents.minY = source.sliceExtents.minY;
|
|
sliceExtents.maxY = source.sliceExtents.maxY;
|
|
sliceExtents.minZ = -source.sliceExtents.maxZ;
|
|
sliceExtents.maxZ = -source.sliceExtents.minZ;
|
|
}
|
|
|
|
//
|
|
//---------------------------------
|
|
// Handle a 90 degree left rotation
|
|
//---------------------------------
|
|
//
|
|
else if (Close_Enough(origin.angularPosition.w, origin.angularPosition.y))
|
|
{
|
|
solidType = Left_90[source.solidType];
|
|
solidExtents.minX = source.solidExtents.minZ;
|
|
solidExtents.maxX = source.solidExtents.maxZ;
|
|
solidExtents.minY = source.solidExtents.minY;
|
|
solidExtents.maxY = source.solidExtents.maxY;
|
|
solidExtents.minZ = -source.solidExtents.maxX;
|
|
solidExtents.maxZ = -source.solidExtents.minX;
|
|
sliceExtents.minX = source.sliceExtents.minZ;
|
|
sliceExtents.maxX = source.sliceExtents.maxZ;
|
|
sliceExtents.minY = source.sliceExtents.minY;
|
|
sliceExtents.maxY = source.sliceExtents.maxY;
|
|
sliceExtents.minZ = -source.sliceExtents.maxX;
|
|
sliceExtents.maxZ = -source.sliceExtents.minX;
|
|
}
|
|
|
|
//
|
|
//----------------------------------
|
|
// Handle a 90 degree right rotation
|
|
//----------------------------------
|
|
//
|
|
else if (Close_Enough(origin.angularPosition.w, -origin.angularPosition.y))
|
|
{
|
|
solidType = Left_270[source.solidType];
|
|
solidExtents.minX = -source.solidExtents.maxZ;
|
|
solidExtents.maxX = -source.solidExtents.minZ;
|
|
solidExtents.minY = source.solidExtents.minY;
|
|
solidExtents.maxY = source.solidExtents.maxY;
|
|
solidExtents.minZ = source.solidExtents.minX;
|
|
solidExtents.maxZ = source.solidExtents.maxX;
|
|
sliceExtents.minX = -source.sliceExtents.maxZ;
|
|
sliceExtents.maxX = -source.sliceExtents.minZ;
|
|
sliceExtents.minY = source.sliceExtents.minY;
|
|
sliceExtents.maxY = source.sliceExtents.maxY;
|
|
sliceExtents.minZ = source.sliceExtents.minX;
|
|
sliceExtents.maxZ = source.sliceExtents.maxX;
|
|
}
|
|
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
// Handle an arbitrary rotation. Make sure that only vertically symetrical
|
|
// solids get here
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
else if (
|
|
source.solidType == BoxedSolid::YAxisCylinderType
|
|
|| source.solidType == BoxedSolid::ConeType
|
|
|| source.solidType == BoxedSolid::SphereType
|
|
)
|
|
{
|
|
solidType = source.solidType;
|
|
Verify(source.solidExtents.minX == source.sliceExtents.minX);
|
|
Verify(source.solidExtents.maxX == source.sliceExtents.maxX);
|
|
Verify(source.solidExtents.minY == source.sliceExtents.minY);
|
|
Verify(source.solidExtents.maxY == source.sliceExtents.maxY);
|
|
Verify(source.solidExtents.minZ == source.sliceExtents.minZ);
|
|
Verify(source.solidExtents.maxZ == source.sliceExtents.maxZ);
|
|
Vector3D center;
|
|
center.x = (source.solidExtents.minX + source.solidExtents.maxX) * 0.5f;
|
|
center.y = source.solidExtents.minY;
|
|
center.z = (source.solidExtents.minZ + source.solidExtents.maxZ) * 0.5f;
|
|
Scalar radius = center.x - source.solidExtents.minX;
|
|
LinearMatrix m;
|
|
m = origin.angularPosition;
|
|
Vector3D translated;
|
|
translated.Multiply(center, m);
|
|
|
|
solidExtents.minX = translated.x - radius;
|
|
solidExtents.maxX = translated.x + radius;
|
|
solidExtents.minY = source.solidExtents.minY;
|
|
solidExtents.maxY = source.solidExtents.maxY;
|
|
solidExtents.minZ = translated.z - radius;
|
|
solidExtents.maxZ = translated.z + radius;
|
|
sliceExtents = solidExtents;
|
|
}
|
|
|
|
//
|
|
//----------------
|
|
// Otherwise, barf
|
|
//----------------
|
|
//
|
|
#if defined(LAB_ONLY)
|
|
else
|
|
{
|
|
Fail("Illegal solid for a non-90 degree rotation!\n");
|
|
}
|
|
#endif
|
|
|
|
solidExtents.minX += origin.linearPosition.x;
|
|
solidExtents.maxX += origin.linearPosition.x;
|
|
solidExtents.minY += origin.linearPosition.y;
|
|
solidExtents.maxY += origin.linearPosition.y;
|
|
solidExtents.minZ += origin.linearPosition.z;
|
|
solidExtents.maxZ += origin.linearPosition.z;
|
|
sliceExtents.minX += origin.linearPosition.x;
|
|
sliceExtents.maxX += origin.linearPosition.x;
|
|
sliceExtents.minY += origin.linearPosition.y;
|
|
sliceExtents.maxY += origin.linearPosition.y;
|
|
sliceExtents.minZ += origin.linearPosition.z;
|
|
sliceExtents.maxZ += origin.linearPosition.z;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
TileResource::Instance(
|
|
const TileResource &source,
|
|
const Origin& origin
|
|
)
|
|
{
|
|
BoxedSolidResource::Instance(source, origin);
|
|
|
|
//
|
|
//-------------------------------
|
|
// Test for a 180 degree rotation
|
|
//-------------------------------
|
|
//
|
|
if (Close_Enough(fabs(origin.angularPosition.y), 1.0f))
|
|
{
|
|
cornerHeight[0] = source.cornerHeight[3];
|
|
cornerHeight[1] = source.cornerHeight[2];
|
|
cornerHeight[2] = source.cornerHeight[1];
|
|
cornerHeight[3] = source.cornerHeight[0];
|
|
}
|
|
|
|
//
|
|
//---------------------------------
|
|
// Handle a 90 degree left rotation
|
|
//---------------------------------
|
|
//
|
|
else if (Close_Enough(origin.angularPosition.w, origin.angularPosition.y))
|
|
{
|
|
cornerHeight[0] = source.cornerHeight[1];
|
|
cornerHeight[1] = source.cornerHeight[3];
|
|
cornerHeight[2] = source.cornerHeight[0];
|
|
cornerHeight[3] = source.cornerHeight[2];
|
|
}
|
|
|
|
//
|
|
//----------------------------------
|
|
// Handle a 90 degree right rotation
|
|
//----------------------------------
|
|
//
|
|
else if (Close_Enough(origin.angularPosition.w, -origin.angularPosition.y))
|
|
{
|
|
cornerHeight[0] = source.cornerHeight[2];
|
|
cornerHeight[1] = source.cornerHeight[0];
|
|
cornerHeight[2] = source.cornerHeight[3];
|
|
cornerHeight[3] = source.cornerHeight[1];
|
|
}
|
|
}
|
|
|
|
//#############################################################################
|
|
|
|
ResourceDescription::ResourceID
|
|
BoxedSolidResource::CreateBoxedSolidStream(
|
|
const char *entry_data,
|
|
ResourceFile *file,
|
|
const ResourceDirectories *resource_directories,
|
|
Logical convert_boxes
|
|
)
|
|
{
|
|
char *filename =
|
|
MakePathedFilename(resource_directories->collisionDirectory, entry_data);
|
|
Register_Pointer(filename);
|
|
|
|
NotationFile *collision_file = new NotationFile(filename);
|
|
Unregister_Pointer(filename);
|
|
delete filename;
|
|
Register_Object(collision_file);
|
|
|
|
|
|
ResourceDescription::ResourceID collision_ID;
|
|
|
|
if (collision_file->PageCount())
|
|
{
|
|
// LAB_ONLY |= collision_file->IsMarkedLabOnly();
|
|
|
|
BoxedSolidList *box_solid_list = new BoxedSolidList;
|
|
Register_Object(box_solid_list);
|
|
|
|
int size = box_solid_list->AddBoxedSolids(collision_file);
|
|
|
|
BoxedSolidResource *boxed_solid_resource =
|
|
new BoxedSolidResource[size];
|
|
Register_Pointer(boxed_solid_resource);
|
|
|
|
int j = 0;
|
|
|
|
|
|
BoundingBoxListNode *p;
|
|
|
|
for (p = box_solid_list->GetRoot(); p; p = p->GetNextNode())
|
|
{
|
|
Verify(j < size);
|
|
Check(p);
|
|
BoxedSolid *box = (BoxedSolid *)p->GetBoundingBox();
|
|
Check(box);
|
|
|
|
boxed_solid_resource[j].materialType = box->materialType;
|
|
|
|
if ((box->solidType == BoxedSolid::BlockType) && (convert_boxes))
|
|
{
|
|
boxed_solid_resource[j].solidType = BoxedSolid::ReducibleBlockType;
|
|
}
|
|
else
|
|
{
|
|
boxed_solid_resource[j].solidType = box->solidType;
|
|
}
|
|
|
|
boxed_solid_resource[j].solidExtents = *box;
|
|
boxed_solid_resource[j].sliceExtents = p->solidSlice;
|
|
boxed_solid_resource[j].recordLength = sizeof(boxed_solid_resource[j]);
|
|
|
|
++j;
|
|
}
|
|
|
|
for (p = box_solid_list->GetRoot(); p; p = p->GetNextNode())
|
|
{
|
|
|
|
Check(p);
|
|
BoxedSolid *box = (BoxedSolid *)p->GetBoundingBox();
|
|
Check(box);
|
|
|
|
Unregister_Object(box);
|
|
delete(box);
|
|
|
|
}
|
|
|
|
ResourceDescription *res_description = file->FindResourceDescription(entry_data,
|
|
ResourceDescription::BoxedSolidStreamResourceType);
|
|
|
|
if(res_description == NULL)
|
|
{
|
|
collision_ID =
|
|
file->AddResource(
|
|
entry_data,
|
|
ResourceDescription::BoxedSolidStreamResourceType,
|
|
1,
|
|
ResourceDescription::Preload,
|
|
boxed_solid_resource,
|
|
size * sizeof(BoxedSolidResource)
|
|
)->resourceID;
|
|
}
|
|
else
|
|
{
|
|
collision_ID = res_description->resourceID;
|
|
}
|
|
|
|
Unregister_Pointer(boxed_solid_resource);
|
|
delete boxed_solid_resource;
|
|
|
|
Unregister_Object(box_solid_list);
|
|
delete box_solid_list;
|
|
|
|
}
|
|
else
|
|
{
|
|
//----------------------------------------------
|
|
// display warning that collision file is empty
|
|
//----------------------------------------------
|
|
DEBUG_STREAM << "** Collision file '" << entry_data <<
|
|
"' empty or not found. **" << endl;
|
|
//----------------------------------------------
|
|
// continue to show all missing collision files
|
|
//----------------------------------------------
|
|
}
|
|
|
|
Unregister_Object(collision_file);
|
|
delete collision_file;
|
|
|
|
return collision_ID;
|
|
}
|
|
//#############################################################################
|
|
//########################## BoxedSolidCollision ########################
|
|
//#############################################################################
|
|
|
|
static const int
|
|
Cant_Occlude[BoxedSolid::SolidTypeCount]=
|
|
{
|
|
0, 1<<(X_Axis|Y_Axis|Z_Axis), 1<<(X_Axis|Z_Axis), 0,
|
|
1<<X_Axis, 1<<Z_Axis, 1<<X_Axis, 1<<Z_Axis,
|
|
1<<X_Axis, 1<<Z_Axis, 1<<X_Axis, 1<<Z_Axis,
|
|
1<<Y_Axis, 1<<Y_Axis, 1<<Y_Axis, 1<<Y_Axis,
|
|
1<<X_Axis, 1<<Y_Axis, 1<<Z_Axis,
|
|
0, 0
|
|
};
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Logical
|
|
BoxedSolidCollision::Occludes(
|
|
BoxedSolidCollision &collision,
|
|
const Vector3D &velocity
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(&collision);
|
|
Check(&velocity);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Check against the three major axes of motion, making sure that the VTV is
|
|
// actually moving in that component
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
for (int axis=X_Axis; axis<=Z_Axis; ++axis)
|
|
{
|
|
if (Small_Enough(velocity[axis]))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// If we cannot guarantee occlusion, do some more testing to see if it is
|
|
// possible to guarantee occlusion on a model-specific basis. This is
|
|
// simply to handle transversal motion across the ramp
|
|
//
|
|
// NOTE: This is a KLUDGE!!! This will not properly handle two ramps side
|
|
// by side of different sizes where the smaller ramp is in the
|
|
// empty portion of the larger ramp
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
BoxedSolid *first = GetTreeVolume();
|
|
BoxedSolid *second = collision.GetTreeVolume();
|
|
Check(first);
|
|
Check(second);
|
|
if (
|
|
(Cant_Occlude[first->solidType] & (1<<axis))
|
|
&& first->solidType != second->solidType
|
|
)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// Figure out what face to check against, and make sure that the face of
|
|
// the possibly occluding slice is nearer than the other slice
|
|
//----------------------------------------------------------------------
|
|
//
|
|
int face = (axis<<1) + (velocity[axis] < 0.0f);
|
|
int opposite_face = face^1;
|
|
if (face&1)
|
|
{
|
|
if (first->solidType == BoxedSolid::BlockType)
|
|
{
|
|
if (collisionSlice[face] <= collision.collisionSlice[face])
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else if (
|
|
collisionSlice[opposite_face] < collision.collisionSlice[face]
|
|
)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (first->solidType == BoxedSolid::BlockType)
|
|
{
|
|
if (collisionSlice[face] >= collision.collisionSlice[face])
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else if (
|
|
collisionSlice[opposite_face] > collision.collisionSlice[face]
|
|
)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
//------------------------------------------------------------------
|
|
// Check the faces on the other axes to make sure that the occluding
|
|
// object at least covers the extent of the occluded object
|
|
//------------------------------------------------------------------
|
|
//
|
|
for (face=0; face<6; ++face)
|
|
{
|
|
if ((face>>1) == axis)
|
|
{
|
|
continue;
|
|
}
|
|
if (face&1)
|
|
{
|
|
if (collisionSlice[face] < collision.collisionSlice[face])
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else if (collisionSlice[face] > collision.collisionSlice[face])
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// If everything checked out, then List[i] occludes List[j]. Stretch the
|
|
// definition of List[i] to include the slice occluded if necessary
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
if (face == 6)
|
|
{
|
|
face = axis<<1;
|
|
if (velocity[axis] > 0.0f)
|
|
{
|
|
++face;
|
|
collisionSlice[face] =
|
|
Max(collisionSlice[face], collision.collisionSlice[face]);
|
|
}
|
|
else
|
|
{
|
|
collisionSlice[face] =
|
|
Min(collisionSlice[face], collision.collisionSlice[face]);
|
|
}
|
|
return True;
|
|
}
|
|
}
|
|
return False;
|
|
}
|
|
|
|
//#############################################################################
|
|
//######################## BoxedSolidCollisionList ######################
|
|
//#############################################################################
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
BoxedSolidCollisionList::ReduceCollisionList(const Vector3D &velocity)
|
|
{
|
|
Check(this);
|
|
Check(&velocity);
|
|
|
|
int
|
|
i,j;
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Fuse the collision slices together into the largest possible chunks based
|
|
// upon the collision model of each of the involved slices. Repeat until no
|
|
// fusings were made in the last pass or only one collision slice remains
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
Logical again = True;
|
|
int collisions = GetCollisionCount();
|
|
phantomCollisions = 0;
|
|
while (again && collisions>1)
|
|
{
|
|
again = False;
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// Check each collision slice against the remaining slices in the list
|
|
//--------------------------------------------------------------------
|
|
//
|
|
for (i=0; i<collisions; ++i)
|
|
{
|
|
for (j=i+1; j<collisions; ++j)
|
|
{
|
|
//
|
|
//-------------------------------------------------------------
|
|
// If the model types are different, these two slices cannot be
|
|
// fused
|
|
//-------------------------------------------------------------
|
|
//
|
|
BoxedSolidCollision *first = &(*this)[i];
|
|
BoxedSolidCollision *second = &(*this)[j];
|
|
if (
|
|
first->GetTreeVolume()->solidType
|
|
!= second->GetTreeVolume()->solidType
|
|
)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
//----------------------------------------------------
|
|
// Make sure that the faces on two sets of sides match
|
|
//----------------------------------------------------
|
|
//
|
|
|
|
int matches = 0;
|
|
int face = -1;
|
|
for (int side=0; side<6; side += 2)
|
|
{
|
|
if (
|
|
first->collisionSlice[side] == second->collisionSlice[side]
|
|
&& first->collisionSlice[side+1]
|
|
== second->collisionSlice[side+1]
|
|
)
|
|
{
|
|
++matches;
|
|
}
|
|
else if (face<0)
|
|
{
|
|
face = side;
|
|
}
|
|
}
|
|
if (matches != 2)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
//----------------------------------------------------------------
|
|
// Check to make sure that the two slices have an opposing face in
|
|
// common, which will allow the slices to be fused
|
|
//----------------------------------------------------------------
|
|
//
|
|
if (
|
|
first->collisionSlice[face] != second->collisionSlice[face+1]
|
|
&& first->collisionSlice[face+1]
|
|
!= second->collisionSlice[face]
|
|
)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
//----------------------------------------------------------------
|
|
// Find the face to fuse, then find out which solid description to
|
|
// use based upon the velocity vector
|
|
//----------------------------------------------------------------
|
|
//
|
|
if (first->collisionSlice[face+1] == second->collisionSlice[face])
|
|
{
|
|
++face;
|
|
}
|
|
BoxedSolid *original = NULL;
|
|
if (
|
|
first->GetTreeVolume() != second->GetTreeVolume()
|
|
&& second->Occludes(*first, velocity)
|
|
)
|
|
{
|
|
original = first->GetTreeVolume();
|
|
first->treeVolume = second->GetTreeVolume();
|
|
}
|
|
|
|
//
|
|
//-------------------------
|
|
// Fuse the blocks together
|
|
//-------------------------
|
|
//
|
|
first->collisionSlice[face] = second->collisionSlice[face];
|
|
|
|
//
|
|
//-----------------------------------------------
|
|
// Erase the second slice from the collision list
|
|
//-----------------------------------------------
|
|
//
|
|
for (int k=j+1; k<collisions; ++k)
|
|
listStart[k-1] = listStart[k];
|
|
++phantomCollisions;
|
|
listStart[--collisions].treeVolume = original;
|
|
--j;
|
|
again = True;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// Check to see if any of the collisions occlude one another if more than
|
|
// one collision slice remains
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
if (collisions>1)
|
|
{
|
|
//
|
|
//--------------------------
|
|
// Erase the occlusion table
|
|
//--------------------------
|
|
//
|
|
Logical* occluded = new Logical[collisions];
|
|
Register_Pointer(occluded);
|
|
BoxedSolid **volumes = new BoxedSolid* [collisions];
|
|
Register_Pointer(volumes);
|
|
for (i=0; i<collisions; ++i)
|
|
occluded[i] = False;
|
|
|
|
//
|
|
//------------------------------------------------------------
|
|
// Check each slice to see if it is occluded by something else
|
|
//------------------------------------------------------------
|
|
//
|
|
for (i=0; i<collisions; ++i)
|
|
{
|
|
for (j=0; j<collisions; ++j)
|
|
{
|
|
if (i==j || occluded[j])
|
|
{
|
|
continue;
|
|
}
|
|
if ((*this)[i].Occludes((*this)[j], velocity))
|
|
{
|
|
occluded[j] = True;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//---------------------------------------------------------
|
|
// Check the occlusion table, and erase any occluded slices
|
|
//---------------------------------------------------------
|
|
//
|
|
j = 0;
|
|
int occludeds = 0;
|
|
for (i=0; i<collisions; ++i)
|
|
{
|
|
if (!occluded[i])
|
|
{
|
|
if (i>j)
|
|
{
|
|
listStart[j] = listStart[i];
|
|
}
|
|
++j;
|
|
}
|
|
else
|
|
{
|
|
volumes[++occludeds] = (BoxedSolid*)listStart[i].treeVolume;
|
|
}
|
|
}
|
|
i = 0;
|
|
while (j<collisions)
|
|
{
|
|
listStart[j++].treeVolume = volumes[i++];
|
|
}
|
|
|
|
phantomCollisions += occludeds;
|
|
Unregister_Pointer(volumes);
|
|
delete[] volumes;
|
|
Unregister_Pointer(occluded);
|
|
delete[] occluded;
|
|
}
|
|
}
|
|
|
|
//#############################################################################
|
|
//########################## BoxedReducibleBlock ########################
|
|
//#############################################################################
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
BoxedReducibleBlock::BoxedReducibleBlock(
|
|
const ExtentBox &extents,
|
|
BoxedSolid::Material material,
|
|
Simulation *owner,
|
|
BoxedSolid *next_solid
|
|
):
|
|
BoxedSolid(extents, ReducibleBlockType, material, owner, next_solid)
|
|
{
|
|
Check_Pointer(this);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
BoxedReducibleBlock::~BoxedReducibleBlock()
|
|
{
|
|
Check_Pointer(this);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Logical
|
|
BoxedReducibleBlock::TestInstance() const
|
|
{
|
|
return solidType == ReducibleBlockType;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Logical
|
|
BoxedReducibleBlock::IntersectsBounded(const ExtentBox &extents)
|
|
{
|
|
Check(this);
|
|
Check(&extents);
|
|
|
|
return ExtentBox::Intersects(extents);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Logical
|
|
BoxedReducibleBlock::ContainsBounded(const Point3D &point)
|
|
{
|
|
Check(this);
|
|
Check(&point);
|
|
|
|
return ExtentBox::Contains(point);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Scalar
|
|
BoxedReducibleBlock::FindDistanceBelowBounded(const Point3D &point)
|
|
{
|
|
Check(this);
|
|
Check(&point);
|
|
|
|
if (
|
|
minX <= point.x && maxX >= point.x && minY <= point.y
|
|
&& minZ <= point.z && maxZ >= point.z
|
|
)
|
|
{
|
|
Scalar result = point.y - maxY;
|
|
return Max(result, 0.0f);
|
|
}
|
|
else
|
|
{
|
|
return -1.0f;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Logical
|
|
BoxedReducibleBlock::HitByBounded(
|
|
Line *line,
|
|
Scalar enters,
|
|
Scalar leaves
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(line);
|
|
|
|
Scalar
|
|
perpendicular,
|
|
drift,
|
|
distance;
|
|
|
|
//
|
|
//--------------------
|
|
// Set up for the test
|
|
//--------------------
|
|
//
|
|
for (int i=0; i<6; ++i)
|
|
{
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// Figure out what axis we are dealing with, then based upon the
|
|
// direction of the face, find out the distance from the origin to the
|
|
// place against the normal, and find out how fast the perpendicular
|
|
// distance changes with a unit movement along the line
|
|
//--------------------------------------------------------------------
|
|
//
|
|
int face = i;
|
|
int axis = face >> 1;
|
|
if (face&1)
|
|
{
|
|
perpendicular = line->origin[axis] - (*this)[face];
|
|
drift = line->direction[axis];
|
|
}
|
|
else
|
|
{
|
|
perpendicular = (*this)[face] - line->origin[axis];
|
|
drift = -line->direction[axis];
|
|
}
|
|
|
|
//
|
|
//-------------------------------------------------------------------
|
|
// If the line is parallel to the face, figure out whether or not the
|
|
// line origin lies within the face's half-space
|
|
//-------------------------------------------------------------------
|
|
//
|
|
if (Small_Enough(drift))
|
|
{
|
|
if (perpendicular > 0.0f)
|
|
{
|
|
return False;
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// If the drift is towards the plane's halfspace, this plane is one of
|
|
// the one through which the line could enter the node
|
|
//--------------------------------------------------------------------
|
|
//
|
|
distance = -perpendicular / drift;
|
|
if (drift < 0.0f)
|
|
{
|
|
if (distance > enters)
|
|
{
|
|
enters = distance;
|
|
}
|
|
if (enters > line->length)
|
|
{
|
|
return False;
|
|
}
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// If the drift is towards the plane's halfspace, this plane is one of
|
|
// the one through which the line could enter the node
|
|
//--------------------------------------------------------------------
|
|
//
|
|
else
|
|
{
|
|
if (distance < leaves)
|
|
{
|
|
leaves = distance;
|
|
}
|
|
if (leaves < 0.0f)
|
|
{
|
|
return False;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// If we exit the loop, then make sure that we actually hit the interior,
|
|
// and let the box figure out if the what happens inside it
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
if (enters <= leaves)
|
|
{
|
|
line->length = Max(enters, 0.0f);
|
|
return True;
|
|
}
|
|
else
|
|
{
|
|
return False;
|
|
}
|
|
}
|
|
|
|
//#############################################################################
|
|
//########################### BoxedSolidList ############################
|
|
//#############################################################################
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
int
|
|
BoxedSolidList::AddBoxedSolids(NotationFile *notation_file)
|
|
{
|
|
char page_name[50];
|
|
int solidnumber = 0;
|
|
int type;
|
|
|
|
BoxedSolidResource boxed_solid_resource;
|
|
BoxedSolid *boxed_solid;
|
|
|
|
|
|
if (!notation_file->GetEntry("COLLISION", "count", &solidnumber))
|
|
{
|
|
DEBUG_STREAM << "No 'COLLISION' entry!!!!!" << endl;
|
|
Exit(AbortExitCodeID);
|
|
}
|
|
|
|
for (int j=0; j < solidnumber; ++j)
|
|
{
|
|
sprintf(page_name, "volume %d", j);
|
|
|
|
if (!notation_file->GetEntry(page_name, "TypeNumber", &type))
|
|
{
|
|
DEBUG_STREAM << "No solid at collision number : " << j << endl;
|
|
Exit(AbortExitCodeID);
|
|
}
|
|
boxed_solid_resource.solidType = (BoxedSolid::Type)type;
|
|
|
|
if (!notation_file->GetEntry(page_name, "MaterialNumber", &type))
|
|
{
|
|
DEBUG_STREAM << "No material at collision number : " << j << endl;
|
|
Exit(AbortExitCodeID);
|
|
}
|
|
|
|
boxed_solid_resource.materialType = (BoxedSolid::Material)type;
|
|
|
|
int errorvalue = 0;
|
|
|
|
errorvalue |= !notation_file->GetEntry(page_name, "extminX", &(boxed_solid_resource.solidExtents.minX));
|
|
errorvalue |= !notation_file->GetEntry(page_name, "extmaxX", &(boxed_solid_resource.solidExtents.maxX));
|
|
errorvalue |= !notation_file->GetEntry(page_name, "extminY", &(boxed_solid_resource.solidExtents.minY));
|
|
errorvalue |= !notation_file->GetEntry(page_name, "extmaxY", &(boxed_solid_resource.solidExtents.maxY));
|
|
errorvalue |= !notation_file->GetEntry(page_name, "extminZ", &(boxed_solid_resource.solidExtents.minZ));
|
|
errorvalue |= !notation_file->GetEntry(page_name, "extmaxZ", &(boxed_solid_resource.solidExtents.maxZ));
|
|
|
|
if ( errorvalue )
|
|
{
|
|
DEBUG_STREAM << "Collision number : " << j
|
|
<< " does not have valid extents\n";
|
|
Exit(AbortExitCodeID);
|
|
}
|
|
|
|
errorvalue = 0;
|
|
errorvalue |= !notation_file->GetEntry(page_name, "slcminX", &(boxed_solid_resource.sliceExtents.minX));
|
|
errorvalue |= !notation_file->GetEntry(page_name, "slcmaxX", &(boxed_solid_resource.sliceExtents.maxX));
|
|
errorvalue |= !notation_file->GetEntry(page_name, "slcminY", &(boxed_solid_resource.sliceExtents.minY));
|
|
errorvalue |= !notation_file->GetEntry(page_name, "slcmaxY", &(boxed_solid_resource.sliceExtents.maxY));
|
|
errorvalue |= !notation_file->GetEntry(page_name, "slcminZ", &(boxed_solid_resource.sliceExtents.minZ));
|
|
errorvalue |= !notation_file->GetEntry(page_name, "slcmaxZ", &(boxed_solid_resource.sliceExtents.maxZ));
|
|
|
|
if ( errorvalue )
|
|
{
|
|
DEBUG_STREAM << "Collision number : " << j
|
|
<< " does not have valid slice extents\n";
|
|
Exit(AbortExitCodeID);
|
|
}
|
|
|
|
|
|
boxed_solid =
|
|
BoxedSolid::MakeBoxedSolid(&boxed_solid_resource, NULL, NULL);
|
|
|
|
Register_Object(boxed_solid);
|
|
|
|
Add(boxed_solid, boxed_solid_resource.sliceExtents);
|
|
}
|
|
|
|
return solidnumber;
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
|
|
#if defined(TEST_CLASS)
|
|
# include "boxsolid.tcp"
|
|
#endif
|
|
|