This commit is contained in:
romkazvo
2023-08-07 19:29:24 +08:00
commit 34d6c5d489
4832 changed files with 1389451 additions and 0 deletions

57
CryPhysics/CryPhysics.cpp Normal file
View File

@@ -0,0 +1,57 @@
// CryPhysics.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
//#include <float.h>
#ifndef GAMECUBE
#ifndef _XBOX
//#if !defined(LINUX)
_ACCESS_POOL;
//#endif//LINUX
#endif //_XBOX
#include <CrtDebugStats.h>
#endif
#include "IPhysics.h"
#include "geoman.h"
#include "bvtree.h"
#include "geometry.h"
#include "rigidbody.h"
#include "physicalplaceholder.h"
#include "physicalentity.h"
#include "physicalworld.h"
float g_costab[SINCOSTABSZ],g_sintab[SINCOSTABSZ];
//////////////////////////////////////////////////////////////////////////
// Pointer to Global ISystem.
static ISystem* gISystem = 0;
ISystem* GetISystem()
{
return gISystem;
}
//////////////////////////////////////////////////////////////////////////
#ifdef _WIN32
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
return TRUE;
}
#endif
#ifndef _XBOX
CRYPHYSICS_API IPhysicalWorld *CreatePhysicalWorld(ISystem *pSystem)
#else
IPhysicalWorld *CreatePhysicalWorld(ISystem *pSystem)
#endif
{
gISystem = pSystem;
g_bHasSSE = (pSystem->GetCPUFlags() & CPUF_SSE)!=0;
for(int i=0; i<SINCOSTABSZ; i++) {
g_costab[i] = cosf(i*(pi*0.5f/SINCOSTABSZ));
g_sintab[i] = sinf(i*(pi*0.5f/SINCOSTABSZ));
}
//_controlfp(_EM_ZERODIVIDE,_MCW_EM);
return new CPhysicalWorld(pSystem->GetILog());
}

22
CryPhysics/CryPhysics.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef cryphysics_h
#define cryphysics_h
#pragma once
#ifndef _XBOX
#ifdef PHYSICS_EXPORTS
#define CRYPHYSICS_API __declspec(dllexport)
#else
#define CRYPHYSICS_API __declspec(dllimport)
#define vector_class Vec3d
#endif
#else
#define CRYPHYSICS_API
#endif
#include "utils.h"
#include "primitives.h"
#include "physinterface.h"
extern "C" CRYPHYSICS_API IPhysicalWorld *CreatePhysicalWorld();
#endif

View File

@@ -0,0 +1,634 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="CryPhysics"
ProjectGUID="{9F51A48A-EE94-4A94-AABA-C0C18B7B8774}"
SccProjectName="Perforce Project"
SccAuxPath=""
SccLocalPath="."
SccProvider="MSSCCI:Perforce SCM">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Profile|Win32"
OutputDirectory="D:\Games\FC\Bin32"
IntermediateDirectory="Profile"
ConfigurationType="2"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2"
WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
Optimization="3"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="1"
OmitFramePointers="TRUE"
EnableFiberSafeOptimizations="FALSE"
OptimizeForProcessor="3"
AdditionalIncludeDirectories="..\CryCommon"
PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;_USRDLL;PHYSICS_EXPORTS;PIII_SSE;ENTITY_PROFILER_ENABLED"
StringPooling="TRUE"
RuntimeLibrary="2"
BufferSecurityCheck="FALSE"
EnableFunctionLevelLinking="FALSE"
EnableEnhancedInstructionSet="0"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile=".\Profile/CryPhysics.pch"
AssemblerListingLocation=".\Profile/"
ObjectFile=".\Profile/"
ProgramDataBaseFileName=".\Profile/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="3"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:I386"
AdditionalDependencies="odbc32.lib odbccp32.lib"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
GenerateDebugInformation="TRUE"
BaseAddress="0x35000000"/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="NDEBUG"
MkTypLibCompatible="TRUE"
SuppressStartupBanner="TRUE"
TargetEnvironment="1"
TypeLibraryName="C:\MasterCD/CryPhysics.tlb"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1033"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Debug|Win32"
OutputDirectory="D:\Games\FC\Bin32"
IntermediateDirectory=".\Debug"
ConfigurationType="2"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
OptimizeForProcessor="0"
AdditionalIncludeDirectories="..\CryCommon"
PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;_USRDLL;PHYSICS_EXPORTS;PIII_SSE;ENTITY_PROFILER_ENABLED"
MinimalRebuild="TRUE"
BasicRuntimeChecks="0"
RuntimeLibrary="3"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile=".\Debug/CryPhysics.pch"
AssemblerListingLocation=".\Debug/"
ObjectFile=".\Debug/"
ProgramDataBaseFileName=".\Debug/"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="4"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:I386"
AdditionalDependencies="odbc32.lib odbccp32.lib"
LinkIncremental="2"
SuppressStartupBanner="TRUE"
GenerateDebugInformation="TRUE"
ImportLibrary="$(IntDir)/$(TargetName).lib"/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="_DEBUG"
MkTypLibCompatible="TRUE"
SuppressStartupBanner="TRUE"
TargetEnvironment="1"
TypeLibraryName=".\Debug/CryPhysics.tlb"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1033"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="D:\Games\FC\Bin32"
IntermediateDirectory="Release"
ConfigurationType="2"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2"
WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
Optimization="3"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="1"
OmitFramePointers="TRUE"
EnableFiberSafeOptimizations="FALSE"
OptimizeForProcessor="3"
AdditionalIncludeDirectories="..\CryCommon"
PreprocessorDefinitions="_RELEASE;NDEBUG;WIN32;_WINDOWS;_USRDLL;PHYSICS_EXPORTS;PIII_SSE"
StringPooling="TRUE"
RuntimeLibrary="2"
BufferSecurityCheck="FALSE"
EnableFunctionLevelLinking="FALSE"
EnableEnhancedInstructionSet="0"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile=".\Release/CryPhysics.pch"
AssemblerListingLocation=".\Release/"
ObjectFile=".\Release/"
ProgramDataBaseFileName=".\Release/"
WarningLevel="3"
SuppressStartupBanner="TRUE"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:I386"
AdditionalDependencies="odbc32.lib odbccp32.lib"
OutputFile=".\Release/CryPhysics.dll"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
ProgramDatabaseFile=".\Release/CryPhysics.pdb"
ImportLibrary="$(IntDir)/$(TargetName).lib"/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="NDEBUG"
MkTypLibCompatible="TRUE"
SuppressStartupBanner="TRUE"
TargetEnvironment="1"
TypeLibraryName=".\Release/CryPhysics.tlb"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1033"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Debug64|Win32"
OutputDirectory="D:\Games\FC\Bin32"
IntermediateDirectory="Debug64"
ConfigurationType="2"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\CryCommon"
PreprocessorDefinitions="_DEBUG;WIN64;_WINDOWS;_USRDLL;PHYSICS_EXPORTS"
BasicRuntimeChecks="0"
RuntimeLibrary="1"
BufferSecurityCheck="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile="$(IntDir)/$(ProjectName).pch"
AssemblerListingLocation="$(IntDir)/"
ObjectFile="$(IntDir)/"
ProgramDataBaseFileName="$(IntDir)/$(ProjectName).pdb"
WarningLevel="3"
SuppressStartupBanner="TRUE"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:AMD64"
AdditionalDependencies="../CryCommon/fSinCos64.lib"
OutputFile="$(OutDir)/$(ProjectName).dll"
LinkIncremental="2"
SuppressStartupBanner="TRUE"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"
LargeAddressAware="2"
ImportLibrary="$(OutDir)/$(ProjectName).lib"/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="_DEBUG"
MkTypLibCompatible="TRUE"
SuppressStartupBanner="TRUE"
TargetEnvironment="1"
TypeLibraryName=".\Debug/CryPhysics.tlb"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1033"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release64|Win32"
OutputDirectory="D:\Games\FC\Bin32"
IntermediateDirectory="Release64"
ConfigurationType="2"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2"
WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/fp:fast /GL"
Optimization="2"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="1"
AdditionalIncludeDirectories="..\CryCommon"
PreprocessorDefinitions="_RELEASE;NDEBUG;WIN64;WIN32;_AMD64_;_WINDOWS;_USRDLL;PHYSICS_EXPORTS"
BasicRuntimeChecks="0"
RuntimeLibrary="2"
BufferSecurityCheck="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile="$(IntDir)/$(ProjectName).pch"
AssemblerListingLocation="$(IntDir)/"
ObjectFile="$(IntDir)/"
ProgramDataBaseFileName="$(IntDir)/$(ProjectName).pdb"
WarningLevel="3"
SuppressStartupBanner="TRUE"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="../CryCommon/fSinCos64.lib"
OutputFile="$(OutDir)/$(ProjectName).dll"
LinkIncremental="1"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"
LargeAddressAware="2"
ImportLibrary="$(OutDir)/$(ProjectName).lib"/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="_DEBUG"
MkTypLibCompatible="TRUE"
SuppressStartupBanner="TRUE"
TargetEnvironment="1"
TypeLibraryName=".\Debug/CryPhysics.tlb"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1033"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Dynamics"
Filter="">
<File
RelativePath="articulatedentity.cpp">
</File>
<File
RelativePath="articulatedentity.h">
</File>
<File
RelativePath=".\livingentity.cpp">
</File>
<File
RelativePath=".\livingentity.h">
</File>
<File
RelativePath=".\particleentity.cpp">
</File>
<File
RelativePath=".\particleentity.h">
</File>
<File
RelativePath=".\physicalentity.cpp">
</File>
<File
RelativePath=".\physicalentity.h">
</File>
<File
RelativePath="physicalplaceholder.cpp">
</File>
<File
RelativePath="physicalplaceholder.h">
</File>
<File
RelativePath=".\physicalworld.cpp">
</File>
<File
RelativePath="physicalworld.h">
</File>
<File
RelativePath=".\rigidbody.cpp">
</File>
<File
RelativePath=".\rigidbody.h">
</File>
<File
RelativePath=".\rigidentity.cpp">
</File>
<File
RelativePath=".\rigidentity.h">
</File>
<File
RelativePath="ropeentity.cpp">
</File>
<File
RelativePath="ropeentity.h">
</File>
<File
RelativePath="softentity.cpp">
</File>
<File
RelativePath="softentity.h">
</File>
<File
RelativePath="wheeledvehicleentity.cpp">
</File>
<File
RelativePath="wheeledvehicleentity.h">
</File>
</Filter>
<Filter
Name="Utils"
Filter="">
<File
RelativePath="boolean2d.cpp">
</File>
<File
RelativePath=".\matrixnm.cpp">
</File>
<File
RelativePath=".\matrixnm.h">
</File>
<File
RelativePath="polynomial.h">
</File>
<File
RelativePath=".\qhull.cpp">
</File>
<File
RelativePath="quotient.h">
</File>
<File
RelativePath=".\utils.cpp">
</File>
<File
RelativePath=".\utils.h">
</File>
<File
RelativePath="vectorn.h">
</File>
</Filter>
<Filter
Name="Collisions"
Filter="">
<File
RelativePath="aabbtree.cpp">
</File>
<File
RelativePath="aabbtree.h">
</File>
<File
RelativePath="boxgeom.cpp">
</File>
<File
RelativePath="boxgeom.h">
</File>
<File
RelativePath="bvtree.h">
</File>
<File
RelativePath="cylindergeom.cpp">
</File>
<File
RelativePath="cylindergeom.h">
</File>
<File
RelativePath="geoman.cpp">
</File>
<File
RelativePath="geoman.h">
</File>
<File
RelativePath="geometries.h">
</File>
<File
RelativePath="geometry.cpp">
</File>
<File
RelativePath="geometry.h">
</File>
<File
RelativePath="heightfieldbv.cpp">
</File>
<File
RelativePath="heightfieldbv.h">
</File>
<File
RelativePath="heightfieldgeom.cpp">
</File>
<File
RelativePath="heightfieldgeom.h">
</File>
<File
RelativePath="intersectionchecks.cpp">
</File>
<File
RelativePath="intersectionchecks.h">
</File>
<File
RelativePath="linunprojectionchecks.cpp">
</File>
<File
RelativePath=".\obbtree.cpp">
</File>
<File
RelativePath=".\obbtree.h">
</File>
<File
RelativePath="overlapchecks.cpp">
</File>
<File
RelativePath="overlapchecks.h">
</File>
<File
RelativePath="raybv.cpp">
</File>
<File
RelativePath="raybv.h">
</File>
<File
RelativePath="raygeom.cpp">
</File>
<File
RelativePath="raygeom.h">
</File>
<File
RelativePath="rotunprojectionchecks.cpp">
</File>
<File
RelativePath="singleboxtree.cpp">
</File>
<File
RelativePath="singleboxtree.h">
</File>
<File
RelativePath="spheregeom.cpp">
</File>
<File
RelativePath="spheregeom.h">
</File>
<File
RelativePath="trimesh.cpp">
</File>
<File
RelativePath="trimesh.h">
</File>
<File
RelativePath="unprojectionchecks.h">
</File>
</Filter>
<File
RelativePath=".\CryPhysics.cpp">
</File>
<File
RelativePath="IPhysics.h">
</File>
<File
RelativePath=".\StdAfx.cpp">
<FileConfiguration
Name="Profile|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Debug64|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Release64|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
</File>
<File
RelativePath=".\StdAfx.h">
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = "file:F:\\Crytek\\CryPhysics\\CryPhysics.vcproj"
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
}

View File

@@ -0,0 +1,396 @@
<?xml version="1.0" encoding = "windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.00"
Name="CryPhysics_XBox"
SccProjectName="&quot;$/Game01/CryPhysics&quot;, NEPAAAAA"
SccAuxPath=""
SccLocalPath="."
SccProvider="MSSCCI:Microsoft Visual SourceSafe">
<Platforms>
<Platform
Name="Xbox"/>
</Platforms>
<Configurations>
<Configuration
Name="Profile|Xbox"
OutputDirectory="Profile"
IntermediateDirectory="Profile"
ConfigurationType="1"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="3"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="1"
OmitFramePointers="TRUE"
AdditionalIncludeDirectories="..\CryCommon"
PreprocessorDefinitions="NDEBUG;_XBOX;_LIB;PHYSICS_EXPORTS"
StringPooling="TRUE"
BufferSecurityCheck="FALSE"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile=".\Profile/CryPhysics.pch"
AssemblerListingLocation=".\Profile/"
ObjectFile=".\Profile/"
ProgramDataBaseFileName=".\Profile/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="3"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:I386"
AdditionalDependencies="odbc32.lib odbccp32.lib"
OutputFile="C:\MasterCD/CryPhysics.dll"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
GenerateDebugInformation="TRUE"
GenerateMapFile="TRUE"
MapFileName=".\Profile/CryPhysics.map"
ImportLibrary="C:\MasterCD/CryPhysics.lib"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="XboxDeploymentTool"/>
<Tool
Name="XboxImageTool"/>
</Configuration>
<Configuration
Name="Debug|Xbox"
OutputDirectory="Debug_XBox"
IntermediateDirectory="Debug_XBox"
ConfigurationType="4"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\CryCommon"
PreprocessorDefinitions="_DEBUG;_XBOX;_LIB;PHYSICS_EXPORTS"
BasicRuntimeChecks="3"
RuntimeLibrary="5"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile="$(IntDir)/CryPhysics.pch"
AssemblerListingLocation=".\Debug_XBox/"
ObjectFile=".\Debug_XBox/"
ProgramDataBaseFileName=".\Debug_XBox/"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="3"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/CryPhysics.lib"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
</Configuration>
<Configuration
Name="Release|Xbox"
OutputDirectory="Release_XBox"
IntermediateDirectory="Release_XBox"
ConfigurationType="4"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2"
WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
Optimization="3"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="1"
OmitFramePointers="TRUE"
AdditionalIncludeDirectories="..\CryCommon"
PreprocessorDefinitions="_RELEASE;NDEBUG;_XBOX;_LIB;PHYSICS_EXPORTS"
StringPooling="TRUE"
RuntimeLibrary="4"
BufferSecurityCheck="FALSE"
EnableFunctionLevelLinking="TRUE"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile="$(IntDir)/CryPhysics.pch"
AssemblerListingLocation="$(IntDir)/"
ObjectFile="$(IntDir)/"
ProgramDataBaseFileName="$(IntDir)/"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="2"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/CryPhysics.lib"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
</Configuration>
</Configurations>
<Files>
<Filter
Name="Dynamics"
Filter="">
<File
RelativePath="articulatedentity.cpp">
</File>
<File
RelativePath="articulatedentity.h">
</File>
<File
RelativePath=".\livingentity.cpp">
</File>
<File
RelativePath=".\livingentity.h">
</File>
<File
RelativePath=".\particleentity.cpp">
</File>
<File
RelativePath=".\particleentity.h">
</File>
<File
RelativePath=".\physicalentity.cpp">
</File>
<File
RelativePath=".\physicalentity.h">
</File>
<File
RelativePath=".\physicalworld.cpp">
</File>
<File
RelativePath="physicalworld.h">
</File>
<File
RelativePath=".\rigidbody.cpp">
</File>
<File
RelativePath=".\rigidbody.h">
</File>
<File
RelativePath=".\rigidentity.cpp">
</File>
<File
RelativePath=".\rigidentity.h">
</File>
<File
RelativePath="ropeentity.cpp">
</File>
<File
RelativePath="ropeentity.h">
</File>
<File
RelativePath="wheeledvehicleentity.cpp">
</File>
<File
RelativePath="wheeledvehicleentity.h">
</File>
</Filter>
<Filter
Name="Utils"
Filter="">
<File
RelativePath="boolean2d.cpp">
</File>
<File
RelativePath=".\matrixnm.cpp">
</File>
<File
RelativePath=".\matrixnm.h">
</File>
<File
RelativePath="polynomial.h">
</File>
<File
RelativePath=".\qhull.cpp">
</File>
<File
RelativePath=".\quotient.h">
</File>
<File
RelativePath=".\utils.cpp">
</File>
<File
RelativePath=".\utils.h">
</File>
<File
RelativePath="vectorn.h">
</File>
</Filter>
<Filter
Name="Collisions"
Filter="">
<File
RelativePath="boxgeom.cpp">
</File>
<File
RelativePath="bvtree.h">
</File>
<File
RelativePath="cylindergeom.cpp">
</File>
<File
RelativePath="cylindergeom.h">
</File>
<File
RelativePath="geoman.cpp">
</File>
<File
RelativePath="geoman.h">
</File>
<File
RelativePath="geometries.h">
</File>
<File
RelativePath="geometry.cpp">
</File>
<File
RelativePath="geometry.h">
</File>
<File
RelativePath="heightfieldbv.cpp">
</File>
<File
RelativePath="heightfieldbv.h">
</File>
<File
RelativePath="heightfieldgeom.cpp">
</File>
<File
RelativePath="heightfieldgeom.h">
</File>
<File
RelativePath="intersectionchecks.cpp">
</File>
<File
RelativePath="intersectionchecks.h">
</File>
<File
RelativePath="linunprojectionchecks.cpp">
</File>
<File
RelativePath=".\obbtree.cpp">
</File>
<File
RelativePath=".\obbtree.h">
</File>
<File
RelativePath="overlapchecks.cpp">
</File>
<File
RelativePath="overlapchecks.h">
</File>
<File
RelativePath="primitives.h">
</File>
<File
RelativePath="raybv.cpp">
</File>
<File
RelativePath="raybv.h">
</File>
<File
RelativePath="raygeom.cpp">
</File>
<File
RelativePath="raygeom.h">
</File>
<File
RelativePath="rotunprojectionchecks.cpp">
</File>
<File
RelativePath="singleboxtree.cpp">
</File>
<File
RelativePath="singleboxtree.h">
</File>
<File
RelativePath="spheregeom.cpp">
</File>
<File
RelativePath="spheregeom.h">
</File>
<File
RelativePath="trimesh.cpp">
</File>
<File
RelativePath="trimesh.h">
</File>
<File
RelativePath="unprojectionchecks.h">
</File>
</Filter>
<File
RelativePath=".\CryPhysics.cpp">
</File>
<File
RelativePath="IPhysics.h">
</File>
<File
RelativePath=".\StdAfx.cpp">
<FileConfiguration
Name="Profile|Xbox">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Xbox">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Xbox">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
</File>
<File
RelativePath=".\StdAfx.h">
</File>
<File
RelativePath="aabbtree.cpp">
</File>
<File
RelativePath="aabbtree.h">
</File>
<File
RelativePath="physicalplaceholder.cpp">
</File>
<File
RelativePath="physicalplaceholder.h">
</File>
<File
RelativePath=".\physinterface.h">
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = "file:F:\\Crytek\\CryPhysics\\CryPhysics_XBox.vcproj"
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
}

30
CryPhysics/IPhysics.h Normal file
View File

@@ -0,0 +1,30 @@
#ifndef cryphysics_h
#define cryphysics_h
#pragma once
#ifdef WIN32
#ifdef PHYSICS_EXPORTS
#define CRYPHYSICS_API __declspec(dllexport)
#else
#define CRYPHYSICS_API __declspec(dllimport)
#endif
#else
#define CRYPHYSICS_API
#endif
#define vector_class Vec3_tpl
#ifndef GAMECUBE
#include <CrySizer.h>
#endif
//#include "utils.h"
#include "Cry_Math.h"
#include "primitives.h"
#include "physinterface.h"
extern "C" CRYPHYSICS_API IPhysicalWorld *CreatePhysicalWorld(struct ISystem *pLog);
#endif

5
CryPhysics/MSSCCPRJ.SCC Normal file
View File

@@ -0,0 +1,5 @@
SCC = This is a source code control file
[CryPhysics.vcproj]
SCC_Aux_Path = "P4SCC#perforce:1666##marcoc_code##PC018"
SCC_Project_Name = Perforce Project

8
CryPhysics/StdAfx.cpp Normal file
View File

@@ -0,0 +1,8 @@
// stdafx.cpp : source file that includes just the standard includes
// CryPhysics.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file

119
CryPhysics/StdAfx.h Normal file
View File

@@ -0,0 +1,119 @@
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#if !defined(AFX_STDAFX_H__4AA14050_1B79_4A11_9D24_4E209BF87E2C__INCLUDED_)
#define AFX_STDAFX_H__4AA14050_1B79_4A11_9D24_4E209BF87E2C__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
//////////////////////////////////////////////////////////////////////////
// THIS MUST BE AT THE VERY BEGINING OF STDAFX.H FILE.
// Disable STL threading support, (makes STL faster)
//////////////////////////////////////////////////////////////////////////
#define _NOTHREADS
#define _STLP_NO_THREADS
//////////////////////////////////////////////////////////////////////////
#pragma warning (disable : 4554 4305 4244)
#include "platform.h"
#include "Cry_Math.h"
#include "Cry_XOptimise.h"
#ifdef GAMECUBE
//#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
//#include <string.h>
//#include <time.h>
#include <dolphin.h>
#include <stdarg.h>
#include "GCDefines.h"
#endif
#ifndef _XBOX
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
#endif
#else
#include <xtl.h>
#endif
#include <stdlib.h>
#include <float.h>
#ifndef NO_CRY_STREAM
#include "Stream.h"
#else
class CStream {
public:
bool WriteBits(BYTE *pBits, DWORD nSize) { return true; }
bool ReadBits(BYTE *pBits, DWORD nSize) { return true; }
bool Write(bool b) { return true; }
bool Write(char c) { return true; }
bool Write(unsigned char uc) { return true; }
bool Write(float f) { return true; }
bool Write(unsigned short us) { return true; }
bool Write(short s) { return true; }
bool Write(int i) { return true; }
bool Write(unsigned int ui) { return true; }
bool Write(const vectorf &v) { return true; }
bool Read(bool &b) { return true; }
bool Read(char &c) { return true; }
bool Read(unsigned char &uc) { return true; }
bool Read(unsigned short &us) { return true; }
bool Read(short &s) { return true; }
bool Read(int &i) { return true; }
bool Read(unsigned int &ui) { return true; }
bool Read(float &f) { return true; }
bool Read(vectorf &v) { return true; }
bool WriteNumberInBits(int n,size_t nSize) { return true; }
bool WriteNumberInBits(unsigned int n,size_t nSize) { return true; }
bool ReadNumberInBits(int &n,size_t nSize) { return true; }
bool ReadNumberInBits(unsigned int &n,size_t nSize) { return true; }
bool Seek(size_t dwPos = 0) { return true; }
size_t GetReadPos() { return 0; }
unsigned char *GetPtr() const { return 0; };
size_t GetSize() const { return 0; }
bool SetSize(size_t indwBitSize) { return true; }
};
#endif
#ifdef WIN64
#undef min
#undef max
#endif
#include <string>
#include <map>
#include "ILog.h"
#include "CrySizer.h"
// TODO: reference additional headers your program requires here
#include "primitives.h"
#include "utils.h"
#include "physinterface.h"
#ifdef _DEBUG
#ifdef WIN32
#include <crtdbg.h>
#define DEBUG_CLIENTBLOCK new( _NORMAL_BLOCK, __FILE__, __LINE__)
#define new DEBUG_CLIENTBLOCK
#endif //WIN32
#endif
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__4AA14050_1B79_4A11_9D24_4E209BF87E2C__INCLUDED_)

516
CryPhysics/aabbtree.cpp Normal file
View File

@@ -0,0 +1,516 @@
#include "stdafx.h"
#include "utils.h"
#include "primitives.h"
#include "bvtree.h"
#include "geometry.h"
#include "aabbtree.h"
#include "trimesh.h"
struct BBoxExt : BBox {
box aboxStatic;
};
BBoxExt g_BBoxExtBuf[64];
int g_BBoxExtBufPos;
void CAABBTree::SetParams(int nMinTrisPerNode, int nMaxTrisPerNode, float skipdim, const matrix3x3f &Basis)
{
m_nMinTrisPerNode = nMinTrisPerNode; m_nMaxTrisPerNode = nMaxTrisPerNode;
m_maxSkipDim = skipdim;
m_Basis = Basis;
m_bOriented = m_Basis.IsIdentity()^1;
}
float CAABBTree::Build(CGeometry *pMesh)
{
m_pMesh = (CTriMesh*)pMesh;
m_pNodes = new AABBnode[m_nNodesAlloc=32];
m_pTri2Node = new int[m_pMesh->m_nTris];
m_nMaxTrisInNode = 0;
m_nNodes = 2;
m_pNodes[0].ntris = m_pNodes[1].ntris = 0;
vectorf ptmin,ptmax,pt;
ptmin = ptmax = m_Basis*m_pMesh->m_pVertices[m_pMesh->m_pIndices[0]];
int i;
for(i=1;i<m_pMesh->m_nTris*3;i++) {
pt = m_Basis*m_pMesh->m_pVertices[m_pMesh->m_pIndices[i]];
ptmin.x = min(ptmin.x,pt.x); ptmax.x = max(ptmax.x,pt.x);
ptmin.y = min(ptmin.y,pt.y); ptmax.y = max(ptmax.y,pt.y);
ptmin.z = min(ptmin.z,pt.z); ptmax.z = max(ptmax.z,pt.z);
}
m_size = (ptmax-ptmin)*0.5f;
m_center = ((ptmax+ptmin)*0.5f)*m_Basis;
m_maxSkipDim *= max(max(m_size.x,m_size.y),m_size.z);
float mindim = m_maxSkipDim*0.001f;
m_size.Set(max_safe(m_size.x,mindim), max_safe(m_size.y,mindim), max_safe(m_size.z,mindim));
float volume = BuildNode(0, 0,m_pMesh->m_nTris, m_Basis*m_center,m_size, 0);
if (m_nNodesAlloc>m_nNodes) {
AABBnode *pNodes = m_pNodes;
memcpy(m_pNodes = new AABBnode[m_nNodesAlloc=m_nNodes], pNodes, sizeof(AABBnode)*m_nNodes);
delete[] pNodes;
}
m_nBitsLog = m_nNodes<=256 ? 3 : 4;
int *pNewTri2Node = new int[(m_pMesh->m_nTris-1>>5-m_nBitsLog)+1];
memset(pNewTri2Node,0,sizeof(int)*((m_pMesh->m_nTris-1>>5-m_nBitsLog)+1));
for(i=0;i<m_pMesh->m_nTris;i++)
pNewTri2Node[i>>5-m_nBitsLog] |= m_pTri2Node[i] << ((i&(1<<5-m_nBitsLog)-1)<<m_nBitsLog);
delete[] m_pTri2Node;
m_pTri2Node = pNewTri2Node;
return volume*8+isneg(63-m_nMaxTrisInNode)*1E10f;
}
float CAABBTree::BuildNode(int iNode, int iTriStart,int nTris, vectorf center,vectorf size, int nDepth)
{
int i,j;
vectorf ptmin(MAX),ptmax(MIN),pt,rsize;
float mindim = max(max(size.x,size.y),size.z)*0.001f;
for(i=iTriStart*3;i<(iTriStart+nTris)*3;i++) {
pt = m_Basis*m_pMesh->m_pVertices[m_pMesh->m_pIndices[i]];
ptmin.x = min_safe(ptmin.x,pt.x); ptmax.x = max_safe(ptmax.x,pt.x);
ptmin.y = min_safe(ptmin.y,pt.y); ptmax.y = max_safe(ptmax.y,pt.y);
ptmin.z = min_safe(ptmin.z,pt.z); ptmax.z = max_safe(ptmax.z,pt.z);
}
ptmin += size-center; ptmax += size-center;
if (size.x>mindim) {
rsize.x = (0.5f*128)/size.x;
m_pNodes[iNode].minx = float2int(min(max(ptmin.x*rsize.x-0.5f,0.0f),127.0f));
m_pNodes[iNode].maxx = float2int(min(max(ptmax.x*rsize.x-0.5f,0.0f),127.0f));
m_pNodes[iNode].minx = min((int)m_pNodes[iNode].minx,(int)m_pNodes[iNode].maxx);
m_pNodes[iNode].maxx = max((int)m_pNodes[iNode].minx,(int)m_pNodes[iNode].maxx);
ptmin.x = m_pNodes[iNode].minx*size.x*(2.0f/128);
ptmax.x = (m_pNodes[iNode].maxx+1)*size.x*(2.0f/128);
center.x += (ptmax.x+ptmin.x)*0.5f-size.x;
size.x = (ptmax.x-ptmin.x)*0.5f;
} else {
m_pNodes[iNode].minx = 0; m_pNodes[iNode].maxx = 127;
}
if (size.y>mindim) {
rsize.y = (0.5f*128)/size.y;
m_pNodes[iNode].miny = float2int(min(max(ptmin.y*rsize.y-0.5f,0.0f),127.0f));
m_pNodes[iNode].maxy = float2int(min(max(ptmax.y*rsize.y-0.5f,0.0f),127.0f));
m_pNodes[iNode].miny = min((int)m_pNodes[iNode].miny,(int)m_pNodes[iNode].maxy);
m_pNodes[iNode].maxy = max((int)m_pNodes[iNode].miny,(int)m_pNodes[iNode].maxy);
ptmin.y = m_pNodes[iNode].miny*size.y*(2.0f/128);
ptmax.y = (m_pNodes[iNode].maxy+1)*size.y*(2.0f/128);
center.y += (ptmax.y+ptmin.y)*0.5f-size.y;
size.y = (ptmax.y-ptmin.y)*0.5f;
} else {
m_pNodes[iNode].miny = 0; m_pNodes[iNode].maxy = 127;
}
if (size.z>mindim) {
rsize.z = (0.5f*128)/size.z;
m_pNodes[iNode].minz = float2int(min(max(ptmin.z*rsize.z-0.5f,0.0f),127.0f));
m_pNodes[iNode].maxz = float2int(min(max(ptmax.z*rsize.z-0.5f,0.0f),127.0f));
m_pNodes[iNode].minz = min((int)m_pNodes[iNode].minz,(int)m_pNodes[iNode].maxz);
m_pNodes[iNode].maxz = max((int)m_pNodes[iNode].minz,(int)m_pNodes[iNode].maxz);
ptmin.z = m_pNodes[iNode].minz*size.z*(2.0f/128);
ptmax.z = (m_pNodes[iNode].maxz+1)*size.z*(2.0f/128);
center.z += (ptmax.z+ptmin.z)*0.5f-size.z;
size.z = (ptmax.z-ptmin.z)*0.5f;
} else {
m_pNodes[iNode].minz = 0; m_pNodes[iNode].maxz = 127;
}
//center += (ptmax+ptmin)*0.5f-size; size = (ptmax-ptmin)*0.5f;
if (nTris<=m_nMaxTrisPerNode) {
m_pNodes[iNode].ichild = iTriStart;
m_pNodes[iNode].ntris = nTris;
m_nMaxTrisInNode = max(m_nMaxTrisInNode, nTris);
m_pNodes[iNode].bSingleColl = isneg(max(max(size.x,size.y),size.z)-m_maxSkipDim);
for(i=iTriStart;i<iTriStart+nTris;i++)
m_pTri2Node[i] = iNode;
return size.volume();
}
#if defined(WIN64) || defined(LINUX64)
volatile // compiler bug workaround?
#endif
int iAxis;
int numtris[3],nTrisAx[3],iPart,iMode[3],idx;
float x0,x1,x2,cx,xlim[2],bounds[3][2],diff[3],axdiff[3];
vectorf axis,c;
for(iAxis=0;iAxis<3;iAxis++) {
if (size[iAxis]<mindim) {
axdiff[iAxis] = -1E10f; nTrisAx[iAxis] = 0;
continue;
}
axis = m_Basis.GetRow(iAxis); cx = center[iAxis];
bounds[0][0]=bounds[1][0]=bounds[2][0] = -size[iAxis];
bounds[0][1]=bounds[1][1]=bounds[2][1] = size[iAxis];
numtris[0]=numtris[1]=numtris[2] = 0;
for(i=iTriStart;i<iTriStart+nTris;i++) {
c = m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3]]+m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3+1]]+
m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3+2]];
x0 = m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3+0]]*axis-cx;
x1 = m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3+1]]*axis-cx;
x2 = m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3+2]]*axis-cx;
xlim[0] = min(min(x0,x1),x2); xlim[1] = max(max(x0,x1),x2);
/*for(j=0,c.zero(),xlim[0]=size[iAxis],xlim[1]=-size[iAxis]; j<3; j++) {
c += m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3+j]];
x = axis*m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3+j]]-cx;
xlim[0] = min(xlim[0],x); xlim[1] = max(xlim[1],x);
}*/
iPart = isneg(xlim[1])^1; // mode0: group all triangles that are entirely below center
bounds[0][iPart] = minmax(bounds[0][iPart],xlim[iPart^1],iPart^1); numtris[0]+=iPart;
iPart = isnonneg(xlim[0]); // mode1: group all triangles that are entirely above center
bounds[1][iPart] = minmax(bounds[1][iPart],xlim[iPart^1],iPart^1); numtris[1]+=iPart;
iPart = isnonneg(((c*axis)*(1.0f/3)-cx)); // mode2: sort triangles basing on centroids only
bounds[2][iPart] = minmax(bounds[2][iPart],xlim[iPart^1],iPart^1); numtris[2]+=iPart;
}
for(i=0;i<3;i++) diff[i] = bounds[i][1]-bounds[i][0]-size[iAxis]*((isneg(numtris[i]-m_nMinTrisPerNode)|isneg(nTris-numtris[i]-m_nMinTrisPerNode))*8);
iMode[iAxis] = idxmax3(diff); nTrisAx[iAxis] = numtris[iMode[iAxis]];
axdiff[iAxis] = diff[iMode[iAxis]]*size[dec_mod3[iAxis]]*size[inc_mod3[iAxis]];
}
iAxis = idxmax3(axdiff);
axis = m_Basis.GetRow(iAxis); cx = center[iAxis];
for(i=j=iTriStart;i<iTriStart+nTris;i++) {
x0 = m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3+0]]*axis-cx;
x1 = m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3+1]]*axis-cx;
x2 = m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3+2]]*axis-cx;
#if 0//def WIN64
if ((unsigned)iAxis >= 3)
OutputDebugString ("iAxis>=3!");
else
if ((unsigned)iMode[iAxis] >= 3)
OutputDebugString("iMode[iAxis]>=3!");
#endif
switch(iMode[iAxis]) {
case 0: iPart = isneg(max(max(x0,x1),x2))^1; break;
case 1: iPart = isnonneg(min(min(x0,x1),x2)); break;
case 2: iPart = isnonneg(x0+x1+x2);
}
if (iPart==0) {
// swap triangles
idx=m_pMesh->m_pIndices[i*3+0]; m_pMesh->m_pIndices[i*3+0]=m_pMesh->m_pIndices[j*3+0]; m_pMesh->m_pIndices[j*3+0]=idx;
idx=m_pMesh->m_pIndices[i*3+1]; m_pMesh->m_pIndices[i*3+1]=m_pMesh->m_pIndices[j*3+1]; m_pMesh->m_pIndices[j*3+1]=idx;
idx=m_pMesh->m_pIndices[i*3+2]; m_pMesh->m_pIndices[i*3+2]=m_pMesh->m_pIndices[j*3+2]; m_pMesh->m_pIndices[j*3+2]=idx;
if (m_pMesh->m_pIds) {
idx=m_pMesh->m_pIds[i]; m_pMesh->m_pIds[i]=m_pMesh->m_pIds[j]; m_pMesh->m_pIds[j]=idx;
}
j++;
}
}
j -= iTriStart;
if (j<m_nMinTrisPerNode || j>nTris-m_nMinTrisPerNode) {
m_pNodes[iNode].ichild = iTriStart;
m_pNodes[iNode].ntris = nTris;
m_nMaxTrisInNode = max(m_nMaxTrisInNode, nTris);
m_pNodes[iNode].bSingleColl = isneg(max(max(size.x,size.y),size.z)-m_maxSkipDim);
for(i=iTriStart;i<iTriStart+nTris;i++)
m_pTri2Node[i] = iNode;
return size.volume();
}
// proceed with the children
if (m_nNodes+2 > m_nNodesAlloc) {
AABBnode *pNodes = m_pNodes;
memcpy(m_pNodes = new AABBnode[m_nNodesAlloc+=32], pNodes, m_nNodes*sizeof(AABBnode));
delete[] pNodes;
}
m_pNodes[iNode].ichild = m_nNodes;
m_pNodes[m_nNodes].ntris = m_pNodes[m_nNodes+1].ntris = 0;
iNode = m_nNodes; m_nNodes += 2;
float volume = 0;
volume += BuildNode(iNode+1, iTriStart+j,nTris-j, center,size, nDepth+1);
volume += BuildNode(iNode, iTriStart,j, center,size, nDepth+1);
return volume;
}
void CAABBTree::SetGeomConvex()
{
for(int i=0;i<m_nNodes;i++)
m_pNodes[i].bSingleColl = 1;
}
void CAABBTree::GetBBox(box *pbox)
{
pbox->Basis = m_Basis;
pbox->bOriented = m_bOriented;
pbox->center = m_center;
pbox->size = m_size;
}
void CAABBTree::GetNodeBV(BV *&pBV,int iNode)
{
pBV = g_BBoxBuf + g_BBoxBufPos++;
pBV->type = box::type;
((BBox*)pBV)->iNode = 0;
((BBox*)pBV)->abox.Basis = m_Basis;
((BBox*)pBV)->abox.bOriented = m_bOriented;
((BBox*)pBV)->abox.center = m_center;
((BBox*)pBV)->abox.size = m_size;
}
void CAABBTree::GetNodeBV(BV *&pBV, const vectorf &sweepdir,float sweepstep, int iNode)
{
pBV = g_BBoxExtBuf; g_BBoxExtBufPos = 0;
pBV->type = box::type;
((BBoxExt*)pBV)->iNode = 0;
box &boxstatic = ((BBoxExt*)pBV)->aboxStatic;
boxstatic.Basis = m_Basis;
boxstatic.bOriented = m_bOriented;
boxstatic.center = m_center;
boxstatic.size = m_size;
ExtrudeBox(&boxstatic, sweepdir,sweepstep, &((BBoxExt*)pBV)->abox);
}
void CAABBTree::GetNodeBV(const matrix3x3f &Rw,const vectorf &offsw,float scalew, BV *&pBV, int iNode)
{
pBV = g_BBoxBuf + g_BBoxBufPos++;
pBV->type = box::type;
pBV->iNode = 0;
((BBox*)pBV)->abox.Basis = m_Basis*Rw.T();
((BBox*)pBV)->abox.bOriented = 1;
((BBox*)pBV)->abox.center = Rw*m_center*scalew + offsw;
((BBox*)pBV)->abox.size = m_size*scalew;
}
float CAABBTree::SplitPriority(const BV* pBV)
{
BBox *pbox = (BBox*)pBV;
return pbox->abox.size.volume()*(m_pNodes[pbox->iNode].ntris-1>>31 & 1);
}
void CAABBTree::GetNodeChildrenBVs(const matrix3x3f &Rw,const vectorf &offsw,float scalew,
const BV *pBV_parent, BV *&pBV_child1,BV *&pBV_child2)
{
BBox *bbox_parent=(BBox*)pBV_parent, *&bbox_child1=(BBox*&)pBV_child1, *&bbox_child2=(BBox*&)pBV_child2;
bbox_child1 = g_BBoxBuf + g_BBoxBufPos++;
bbox_child2 = g_BBoxBuf + g_BBoxBufPos++;
bbox_child2->iNode = (bbox_child1->iNode = m_pNodes[bbox_parent->iNode].ichild)+1;
bbox_child1->type = bbox_child2->type = box::type;
bbox_child1->abox.Basis = bbox_parent->abox.Basis; bbox_child2->abox.Basis = bbox_parent->abox.Basis;
bbox_child1->abox.bOriented = bbox_child2->abox.bOriented = 1;
int ichild = bbox_child1->iNode;
const vectorf size=bbox_parent->abox.size, center=bbox_parent->abox.center;
vectorf ptmax,ptmin;
ptmin.x = m_pNodes[ichild].minx*size.x*(2.0/128);
ptmax.x = (m_pNodes[ichild].maxx+1)*size.x*(2.0/128);
ptmin.y = m_pNodes[ichild].miny*size.y*(2.0/128);
ptmax.y = (m_pNodes[ichild].maxy+1)*size.y*(2.0/128);
ptmin.z = m_pNodes[ichild].minz*size.z*(2.0/128);
ptmax.z = (m_pNodes[ichild].maxz+1)*size.z*(2.0/128);
bbox_child1->abox.center = center+((ptmax+ptmin)*0.5f-size)*bbox_parent->abox.Basis;
bbox_child1->abox.size = (ptmax-ptmin)*0.5f;
ptmin.x = m_pNodes[ichild+1].minx*size.x*(2.0/128);
ptmax.x = (m_pNodes[ichild+1].maxx+1)*size.x*(2.0/128);
ptmin.y = m_pNodes[ichild+1].miny*size.y*(2.0/128);
ptmax.y = (m_pNodes[ichild+1].maxy+1)*size.y*(2.0/128);
ptmin.z = m_pNodes[ichild+1].minz*size.z*(2.0/128);
ptmax.z = (m_pNodes[ichild+1].maxz+1)*size.z*(2.0/128);
bbox_child2->abox.center = center+((ptmax+ptmin)*0.5f-size)*bbox_parent->abox.Basis;
bbox_child2->abox.size = (ptmax-ptmin)*0.5f;
}
void CAABBTree::GetNodeChildrenBVs(const BV *pBV_parent, BV *&pBV_child1,BV *&pBV_child2)
{
BBox *bbox_parent=(BBox*)pBV_parent, *&bbox_child1=(BBox*&)pBV_child1, *&bbox_child2=(BBox*&)pBV_child2;
bbox_child1 = g_BBoxBuf + g_BBoxBufPos++;
bbox_child2 = g_BBoxBuf + g_BBoxBufPos++;
bbox_child2->iNode = (bbox_child1->iNode = m_pNodes[bbox_parent->iNode].ichild)+1;
bbox_child1->type = bbox_child2->type = box::type;
if (bbox_child1->abox.bOriented = bbox_child2->abox.bOriented = bbox_parent->abox.bOriented) {
bbox_child1->abox.Basis = bbox_parent->abox.Basis;
bbox_child2->abox.Basis = bbox_parent->abox.Basis;
}
int ichild = bbox_child1->iNode;
const vectorf size=bbox_parent->abox.size, center=bbox_parent->abox.center;
vectorf ptmax,ptmin;
ptmin.x = m_pNodes[ichild].minx*size.x*(2.0/128);
ptmax.x = (m_pNodes[ichild].maxx+1)*size.x*(2.0/128);
ptmin.y = m_pNodes[ichild].miny*size.y*(2.0/128);
ptmax.y = (m_pNodes[ichild].maxy+1)*size.y*(2.0/128);
ptmin.z = m_pNodes[ichild].minz*size.z*(2.0/128);
ptmax.z = (m_pNodes[ichild].maxz+1)*size.z*(2.0/128);
if (bbox_parent->abox.bOriented)
bbox_child1->abox.center = center+((ptmax+ptmin)*0.5f-size)*bbox_parent->abox.Basis;
else
bbox_child1->abox.center = center+((ptmax+ptmin)*0.5f-size);
bbox_child1->abox.size = (ptmax-ptmin)*0.5f;
ptmin.x = m_pNodes[ichild+1].minx*size.x*(2.0/128);
ptmax.x = (m_pNodes[ichild+1].maxx+1)*size.x*(2.0/128);
ptmin.y = m_pNodes[ichild+1].miny*size.y*(2.0/128);
ptmax.y = (m_pNodes[ichild+1].maxy+1)*size.y*(2.0/128);
ptmin.z = m_pNodes[ichild+1].minz*size.z*(2.0/128);
ptmax.z = (m_pNodes[ichild+1].maxz+1)*size.z*(2.0/128);
if (bbox_parent->abox.bOriented)
bbox_child2->abox.center = center+((ptmax+ptmin)*0.5f-size)*bbox_parent->abox.Basis;
else
bbox_child2->abox.center = center+((ptmax+ptmin)*0.5f-size);
bbox_child2->abox.size = (ptmax-ptmin)*0.5f;
}
void CAABBTree::GetNodeChildrenBVs(const BV *pBV_parent, const vectorf &sweepdir,float sweepstep, BV *&pBV_child1,BV *&pBV_child2)
{
BBoxExt *bbox_parent=(BBoxExt*)pBV_parent, *&bbox_child1=(BBoxExt*&)pBV_child1, *&bbox_child2=(BBoxExt*&)pBV_child2;
bbox_child1 = g_BBoxExtBuf + g_BBoxExtBufPos++;
bbox_child2 = g_BBoxExtBuf + g_BBoxExtBufPos++;
bbox_child2->iNode = (bbox_child1->iNode = m_pNodes[bbox_parent->iNode].ichild)+1;
bbox_child1->type = bbox_child2->type = box::type;
if (bbox_child1->aboxStatic.bOriented = bbox_child2->aboxStatic.bOriented = bbox_parent->aboxStatic.bOriented) {
bbox_child1->aboxStatic.Basis = bbox_parent->aboxStatic.Basis;
bbox_child2->aboxStatic.Basis = bbox_parent->aboxStatic.Basis;
}
int ichild = bbox_child1->iNode;
const vectorf size=bbox_parent->aboxStatic.size, center=bbox_parent->aboxStatic.center;
vectorf ptmax,ptmin;
ptmin.x = m_pNodes[ichild].minx*size.x*(2.0/128);
ptmax.x = (m_pNodes[ichild].maxx+1)*size.x*(2.0/128);
ptmin.y = m_pNodes[ichild].miny*size.y*(2.0/128);
ptmax.y = (m_pNodes[ichild].maxy+1)*size.y*(2.0/128);
ptmin.z = m_pNodes[ichild].minz*size.z*(2.0/128);
ptmax.z = (m_pNodes[ichild].maxz+1)*size.z*(2.0/128);
if (bbox_parent->aboxStatic.bOriented)
bbox_child1->aboxStatic.center = center+((ptmax+ptmin)*0.5f-size)*bbox_parent->aboxStatic.Basis;
else
bbox_child1->aboxStatic.center = center+((ptmax+ptmin)*0.5f-size);
bbox_child1->aboxStatic.size = (ptmax-ptmin)*0.5f;
ExtrudeBox(&bbox_child1->aboxStatic, sweepdir,sweepstep, &bbox_child1->abox);
bbox_child1->abox.bOriented = 1+bbox_child1->iNode;
ptmin.x = m_pNodes[ichild+1].minx*size.x*(2.0/128);
ptmax.x = (m_pNodes[ichild+1].maxx+1)*size.x*(2.0/128);
ptmin.y = m_pNodes[ichild+1].miny*size.y*(2.0/128);
ptmax.y = (m_pNodes[ichild+1].maxy+1)*size.y*(2.0/128);
ptmin.z = m_pNodes[ichild+1].minz*size.z*(2.0/128);
ptmax.z = (m_pNodes[ichild+1].maxz+1)*size.z*(2.0/128);
if (bbox_parent->abox.bOriented)
bbox_child2->aboxStatic.center = center+((ptmax+ptmin)*0.5f-size)*bbox_parent->aboxStatic.Basis;
else
bbox_child2->aboxStatic.center = center+((ptmax+ptmin)*0.5f-size);
bbox_child2->aboxStatic.size = (ptmax-ptmin)*0.5f;
ExtrudeBox(&bbox_child2->aboxStatic, sweepdir,sweepstep, &bbox_child2->abox);
bbox_child2->abox.bOriented = 1+bbox_child2->iNode;
}
void CAABBTree::ReleaseLastBVs()
{
g_BBoxBufPos-=2;
}
void CAABBTree::ReleaseLastSweptBVs()
{
g_BBoxExtBufPos-=2;
}
int CAABBTree::GetNodeContents(int iNode, BV *pBVCollider,int bColliderUsed,int bColliderLocal,
geometry_under_test *pGTest,geometry_under_test *pGTestOp)
{
return m_pMesh->GetPrimitiveList(m_pNodes[iNode].ichild,m_pNodes[iNode].ntris, pBVCollider->type,*pBVCollider,bColliderLocal, pGTest,pGTestOp,
pGTest->primbuf,pGTest->idbuf);
}
void CAABBTree::MarkUsedTriangle(int itri, geometry_under_test *pGTest)
{
if (!pGTest->pUsedNodesMap) return;
int iNode = m_pTri2Node[itri>>5-m_nBitsLog]>>((itri&(1<<5-m_nBitsLog)-1)<<m_nBitsLog) & (1<<(1<<m_nBitsLog))-1;
if (m_pNodes[iNode].bSingleColl) {
pGTest->pUsedNodesMap[iNode>>5] |= 1<<(iNode&31);
pGTest->pUsedNodesIdx[pGTest->nUsedNodes = min(pGTest->nUsedNodes+1,pGTest->nMaxUsedNodes-1)] = iNode;
pGTest->bCurNodeUsed = 1;
}
}
int CAABBTree::PrepareForIntersectionTest(geometry_under_test *pGTest)
{
if (m_maxSkipDim<=0) {
pGTest->pUsedNodesMap = 0;
pGTest->pUsedNodesIdx = 0;
pGTest->nMaxUsedNodes = 0;
} else {
int mapsz = (m_nNodes-1>>5) + 1;
if (mapsz<=(int)(sizeof(g_UsedNodesMap)/sizeof(g_UsedNodesMap[0]))-g_UsedNodesMapPos) {
pGTest->pUsedNodesMap = g_UsedNodesMap+g_UsedNodesMapPos; g_UsedNodesMapPos += mapsz;
} else
pGTest->pUsedNodesMap = new int[mapsz];
pGTest->pUsedNodesIdx = g_UsedNodesIdx+g_UsedNodesIdxPos;
pGTest->nMaxUsedNodes = min(32,sizeof(g_UsedNodesIdx)/sizeof(g_UsedNodesIdx[0])-g_UsedNodesIdxPos);
g_UsedNodesIdxPos += pGTest->nMaxUsedNodes;
}
pGTest->nUsedNodes = -1;
return 1;
}
void CAABBTree::CleanupAfterIntersectionTest(geometry_under_test *pGTest)
{
if (!pGTest->pUsedNodesMap)
return;
if ((unsigned int)(pGTest->pUsedNodesMap-g_UsedNodesMap) > (unsigned int)sizeof(g_UsedNodesMap)/sizeof(g_UsedNodesMap[0])) {
delete[] pGTest->pUsedNodesMap; return;
}
if (pGTest->nUsedNodes < pGTest->nMaxUsedNodes-1) {
for(int i=0;i<=pGTest->nUsedNodes;i++)
pGTest->pUsedNodesMap[pGTest->pUsedNodesIdx[i]>>5] &= ~(1<<(pGTest->pUsedNodesIdx[i]&31));
} else
memset(pGTest->pUsedNodesMap, 0, ((m_nNodes-1>>5)+1)*4);
}
void CAABBTree::GetMemoryStatistics(ICrySizer *pSizer)
{
SIZER_COMPONENT_NAME(pSizer, "AABB trees");
pSizer->AddObject(this, sizeof(CAABBTree));
pSizer->AddObject(m_pNodes, m_nNodesAlloc*sizeof(m_pNodes[0]));
if (m_pTri2Node)
pSizer->AddObject(m_pTri2Node, ((m_pMesh->m_nTris-1>>5-m_nBitsLog)+1)*sizeof(int));
}
void CAABBTree::Save(CMemStream &stm)
{
stm.Write(m_nNodes);
stm.Write(m_pNodes, m_nNodes*sizeof(m_pNodes[0]));
stm.Write(m_center);
stm.Write(m_size);
stm.Write(m_Basis);
stm.Write(m_nMaxTrisInNode);
stm.Write(m_nMinTrisPerNode);
stm.Write(m_nMaxTrisPerNode);
stm.Write(m_maxSkipDim);
}
void CAABBTree::Load(CMemStream &stm, CGeometry *pGeom)
{
m_pMesh = (CTriMesh*)pGeom;
stm.Read(m_nNodes);
m_pNodes = new AABBnode[m_nNodesAlloc=m_nNodes];
stm.Read(m_pNodes, m_nNodes*sizeof(m_pNodes[0]));
m_pTri2Node = new int[(m_pMesh->m_nTris-1>>5-m_nBitsLog)+1];
memset(m_pTri2Node,0,sizeof(int)*((m_pMesh->m_nTris-1>>5-m_nBitsLog)+1));
for(int i=0;i<m_nNodes;i++) for(int j=0;j<(int)m_pNodes[i].ntris;j++)
m_pTri2Node[m_pNodes[i].ichild+j>>5-m_nBitsLog] |= i << ((m_pNodes[i].ichild+j&(1<<5-m_nBitsLog)-1)<<m_nBitsLog);
stm.Read(m_center);
stm.Read(m_size);
stm.Read(m_Basis);
stm.Read(m_nMaxTrisInNode);
stm.Read(m_nMinTrisPerNode);
stm.Read(m_nMaxTrisPerNode);
stm.Read(m_maxSkipDim);
}

69
CryPhysics/aabbtree.h Normal file
View File

@@ -0,0 +1,69 @@
#ifndef aabbtree_h
#define aabbtree_h
struct AABBnode {
unsigned int minx : 7;
unsigned int maxx : 7;
unsigned int miny : 7;
unsigned int maxy : 7;
unsigned int minz : 7;
unsigned int maxz : 7;
unsigned int ichild : 15;
unsigned int ntris : 6;
unsigned int bSingleColl : 1;
};
class CTriMesh;
class CAABBTree : public CBVTree {
public:
CAABBTree() {}
virtual ~CAABBTree() {
if (m_pNodes) delete[] m_pNodes; m_pNodes=0;
if (m_pTri2Node) delete[] m_pTri2Node; m_pTri2Node=0;
}
virtual int GetType() { return BVT_AABB; }
float Build(CGeometry *pMesh);
virtual void SetGeomConvex();
void SetParams(int nMinTrisPerNode,int nMaxTrisPerNode, float skipdim, const matrix3x3f &Basis);
float BuildNode(int iNode, int iTriStart,int nTris, vectorf center,vectorf size, int nDepth);
virtual int PrepareForIntersectionTest(geometry_under_test *pGTest);
virtual void CleanupAfterIntersectionTest(geometry_under_test *pGTest);
virtual void GetBBox(box *pbox);
virtual int MaxPrimsInNode() { return m_nMaxTrisInNode; }
virtual void GetNodeBV(BV *&pBV, int iNode=0);
virtual void GetNodeBV(BV *&pBV, const vectorf &sweepdir,float sweepstep, int iNode=0);
virtual void GetNodeBV(const matrix3x3f &Rw,const vectorf &offsw,float scalew, BV *&pBV, int iNode=0);
virtual void GetNodeBV(const matrix3x3f &Rw,const vectorf &offsw,float scalew, BV *&pBV, const vectorf &sweepdir,float sweepstep, int iNode=0) {}
virtual float SplitPriority(const BV* pBV);
virtual void GetNodeChildrenBVs(const matrix3x3f &Rw,const vectorf &offsw,float scalew, const BV *pBV_parent, BV *&pBV_child1,BV *&pBV_child2);
virtual void GetNodeChildrenBVs(const BV *pBV_parent, BV *&pBV_child1,BV *&pBV_child2);
virtual void GetNodeChildrenBVs(const BV *pBV_parent, const vectorf &sweepdir,float sweepstep, BV *&pBV_child1,BV *&pBV_child2);
virtual void ReleaseLastBVs();
virtual void ReleaseLastSweptBVs();
virtual int GetNodeContents(int iNode, BV *pBVCollider,int bColliderUsed,int bColliderLocal,
geometry_under_test *pGTest,geometry_under_test *pGTestOp);
virtual int GetNodeContentsIdx(int iNode, int &iStartPrim) { iStartPrim = m_pNodes[iNode].ichild; return m_pNodes[iNode].ntris; }
virtual void MarkUsedTriangle(int itri, geometry_under_test *pGTest);
virtual void GetMemoryStatistics(ICrySizer *pSizer);
virtual void Save(CMemStream &stm);
virtual void Load(CMemStream &stm, CGeometry *pGeom);
CTriMesh *m_pMesh;
AABBnode *m_pNodes;
int m_nNodes,m_nNodesAlloc;
vectorf m_center;
vectorf m_size;
matrix3x3f m_Basis;
int m_bOriented;
int *m_pTri2Node,m_nBitsLog;
int m_nMaxTrisPerNode,m_nMinTrisPerNode;
int m_nMaxTrisInNode;
float m_maxSkipDim;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,218 @@
//////////////////////////////////////////////////////////////////////
//
// Articulated Entity header
//
// File: articulatedentity.h
// Description : CArticulatedEntity class declaration
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#ifndef articulatedentity_h
#define articulatedentity_h
#pragma once
struct featherstone_data {
vectori qidx2axidx,axidx2qidx;
vectorf Ya_vec[2];
vectorf dv_vec[2];
vectorf s_vec[3][2];
vectorf Q;
float qinv[9];
float qinv_down[9];
float s[18];
DEFINE_ALIGNED_DATA( float, Ia[6][6], 16 );
float Ia_s[18];
DEFINE_ALIGNED_DATA( float, Ia_s_qinv_sT[6][6], 16 );
DEFINE_ALIGNED_DATA( float, s_qinv_sT[6][6], 16 );
DEFINE_ALIGNED_DATA( float, s_qinv_sT_Ia[6][6], 16 );
float qinv_sT[3][6];
float qinv_sT_Ia[3][6];
DEFINE_ALIGNED_DATA( float, Iinv[6][6], 16 );
};
struct ae_joint {
ae_joint() {
nChildren=nChildrenTree=0; iParent=-2; idbody=-1;
q.zero(); qext.zero(); dq.zero(); dqext.zero(); ddq.zero();
MARK_UNUSED dq_req.x,dq_req.y,dq_req.z; dq_limit.zero();
bounciness.zero(); ks.zero(); kd.zero();
qdashpot.zero(); kdashpot.zero();
limits[0].Set(-1E10,-1E10,-1E10);
limits[1].Set(1E10,1E10,1E10);
flags=all_angles_locked;
quat0.SetIdentity();
Pext.zero(); Lext.zero();
Pimpact.zero(); Limpact.zero();
//fs.Q.zero(); fs.Ya_vec[0].zero(); fs.Ya_vec[1].zero();
//matrix3x3f(fs.qinv).identity();
nActiveAngles = nPotentialAngles = 0;
pivot[0].zero(); pivot[1].zero();
iLevel = 0;
iContacts = 0;
iStartPart = nParts = 0;
dv_body.zero(); dw_body.zero();
selfCollMask = 0;
fs = 0; fsbuf = 0;
bQuat0Changed = 0;
}
~ae_joint() {
if (fsbuf) delete fsbuf;
}
vectorf q;
vectorf qext;
vectorf dq;
vectorf dqext;
vectorf dq_req;
vectorf dq_limit;
vectorf ddq;
quaternionf quat;
vectorf prev_q,prev_dq;
vectorf prev_pos,prev_v,prev_w;
quaternionf prev_qrot;
vectorf q0;
unsigned int flags;
quaternionf quat0;
vectorf limits[2];
vectorf bounciness;
vectorf ks,kd;
vectorf qdashpot,kdashpot;
vectorf pivot[2];
vectorf hingePivot[2];
int iStartPart,nParts;
int iParent;
int nChildren,nChildrenTree;
int iLevel;
masktype selfCollMask;
masktype iContacts;
int bAwake;
int bQuat0Changed;
int bHasExtContacts;
int idbody;
RigidBody body;
vectorf dv_body,dw_body;
vectorf Pext,Lext;
vectorf Pimpact,Limpact;
int nActiveAngles,nPotentialAngles;
vectorf rotaxes[3];
matrix3x3f I;
featherstone_data *fs;
void *fsbuf;
};
struct ae_part_info {
quaternionf q0;
vectorf pos0;
int iJoint;
int idbody;
};
class CArticulatedEntity : public CRigidEntity, public IRigidBodyOwner {
public:
CArticulatedEntity(CPhysicalWorld *pworld);
virtual ~CArticulatedEntity();
virtual pe_type GetType() { return PE_ARTICULATED; }
virtual void AlertNeighbourhoodND();
virtual int AddGeometry(phys_geometry *pgeom, pe_geomparams* params,int id=-1);
virtual void RemoveGeometry(int id);
virtual int SetParams(pe_params *_params);
virtual int GetParams(pe_params *_params);
virtual int GetStatus(pe_status *_status);
virtual int Action(pe_action*);
virtual RigidBody *GetRigidBody(int ipart=-1);
virtual void GetContactMatrix(const vectorf &pt, int ipart, matrix3x3f &K);
virtual void AddImpulseAtContact(entity_contact *pcontact, int iop, const vectorf &dP) {};
virtual vectorf GetVelocityAtContact(entity_contact *pcontact, int iop) { return vectorf(zero); };
virtual int OnRegisterContact(entity_contact *pcontact, int iop);
virtual void OnSolverEvent(int iEvent) {};
virtual void GetMemoryStatistics(ICrySizer *pSizer);
enum snapver { SNAPSHOT_VERSION = 6 };
virtual int GetStateSnapshot(CStream &stm, float time_back=0,int flags=0);
virtual int SetStateFromSnapshot(CStream &stm, int flags);
virtual float GetMaxTimeStep(float time_interval);
virtual int Step(float time_interval);
virtual void StepBack(float time_interval);
virtual int RegisterContacts(float time_interval,int nMaxPlaneContacts);
virtual int Update(float time_interval, float damping);
virtual float CalcEnergy(float time_interval);
virtual float GetDamping(float time_interval);
virtual int GetPotentialColliders(CPhysicalEntity **&pentlist);
virtual int CheckSelfCollision(int ipart0,int ipart1);
virtual int IsAwake(int ipart=-1);
virtual void RecomputeMassDistribution(int ipart=-1,int bMassChanged=1);
void SyncWithHost(int bRecalcJoints,float time_interval);
void SyncBodyWithJoint(int idx, int flags=3);
void SyncJointWithBody(int idx, int flags=1);
void UpdateJointRotationAxes(int idx);
void CheckForGimbalLock(int idx);
int GetUnprojAxis(int idx, vectorf &axis);
int StepJoint(int idx, float time_interval,masktype &contact_mask,int &bBounced, int bFlying);
void JointListUpdated();
int CalcBodyZa(int idx, float time_interval, vectornf &Za_change);
int CalcBodyIa(int idx, matrixf& Ia_change);
void CalcBodiesIinv(int bLockLimits);
int CollectPendingImpulses(int idx,int &bNotZero);
void PropagateImpulses(const vectorf &dv,int bLockLimits=0);
void CalcVelocityChanges(float time_interval, const vectorf &dv,const vectorf &dw);
void GetJointTorqueResponseMatrix(int idx, matrix3x3f &K);
int IsChildOf(int idx, int iParent) { return isnonneg(iParent) & isneg(iParent-idx) & isneg(idx-iParent-m_joints[iParent].nChildrenTree-1); }
entity_contact *CreateConstraintContact(int idx);
ae_part_info *m_infos;
ae_joint *m_joints;
int m_nJoints, m_nJointsAlloc;
vectorf m_posPivot, m_offsPivot;
vectorf m_acc,m_wacc;
matrix3x3f m_M0inv;
vectorf m_Ya_vec[2];
float m_simTime,m_simTimeAux;
float m_scaleBounceResponse;
int m_bGrounded;
int m_bInheritVel;
CPhysicalEntity *m_pHost;
vectorf m_posHostPivot;
int m_bCheckCollisions;
int m_bCollisionResp;
int m_bExertImpulse;
int m_iSimType,m_iSimTypeLyingMode;
int m_iSimTypeCur;
int m_iSimTypeOverride;
int m_bIaReady;
int m_bPartPosForced;
int m_bFastLimbs;
int m_bExpandHinges;
float m_maxPenetrationCur;
int m_bUsingUnproj;
vectorf m_prev_pos,m_prev_vel;
int m_bUpdateBodies;
int m_nDynContacts,m_bInGroup;
int m_nCollLyingMode;
vectorf m_gravityLyingMode;
float m_dampingLyingMode;
float m_EminLyingMode;
int m_nContacts;
CPhysicalEntity **m_pCollEntList;
int m_nCollEnts;
};
#endif

268
CryPhysics/boolean2d.cpp Normal file
View File

@@ -0,0 +1,268 @@
#include "stdafx.h"
#include "utils.h"
vector2df g_BoolPtBuf[4096];
int g_BoolIdBuf[4096];
int g_BoolGrid[4096];
unsigned int g_BoolHash[8192];
struct inters2d {
vector2df pt;
int iedge[2];
};
inters2d g_BoolInters[256];
inline int line_seg_inters(const vector2df *seg0, const vector2df *seg1, vector2df *ptres)
{
float denom,t0,t1,sg;
vector2df dp0,dp1,ds;
dp0 = seg0[1]-seg0[0]; dp1 = seg1[1]-seg1[0]; ds = seg1[0]-seg0[0];
denom = dp0^dp1;
if (sqr(denom) > 1E-6f*dp0.len2()*dp1.len2()) { // stable intersection
t0 = ds^dp1; t1 = ds^dp0;
sg = sgnnz(denom); denom*=sg; t0*=sg; t1*=sg;
if (isneg(fabs_tpl(t0*2-denom)-denom) & isneg(fabs_tpl(t1*2-denom)-denom)) {
ptres[0] = seg0[0] + dp0*(t0/denom); return 1;
} else return 0;
}
if (sqr(ds^dp0) < 1E-6f*ds.len2()*dp0.len2()) { // segments are [almost] parallel and touching
float t[2][2]; const vector2df *ppt[2][2]; int idir;
t[0][0]=0; t[0][1]=dp0.len2(); ppt[0][0]=seg0; ppt[0][1]=seg0+1;
t0=(seg1[0]-seg0[0])*dp0; t1=(seg1[1]-seg0[0])*dp0;
idir = isneg(t1-t0); t[1][idir]=t0; t[1][idir^1]=t0; ppt[1][idir]=seg1; ppt[1][idir^1]=seg1+1;
if (max(t[0][0],t[1][0])>min(t[0][1],t[1][1]))
return 0;
ptres[0] = *ppt[0][isneg(t[0][0]-t[1][0])];
ptres[1] = *ppt[1][isneg(t[1][1]-t[0][1])];
return 2;
}
return 0;
}
inline vector2di& get_cell(const vector2df &pt, const vector2df &rstep, vector2di &ipt)
{
ipt.set(float2int(pt.x*rstep.x-0.5f),float2int(pt.y*rstep.y-0.5f));
return ipt;
}
inline void get_rect(const vector2di &ipt0,const vector2di &ipt1,vector2di *irect,const vector2di &isz)
{
irect[0].x = max(0,min(ipt0.x,ipt1.x)); irect[0].y = min(isz.y,max(0,min(ipt0.y,ipt1.y)));
irect[1].x = min(isz.x-1,max(ipt0.x,ipt1.x)); irect[1].y = min(isz.y,max(ipt0.y,ipt1.y));
}
inline int check_if_inside(int iobj, vector2di &ipt,const vector2di &isz,const vector2df *ptsrc, const vector2df &pt)
{
int bInside,i,bStop=0;
vector2df pt0,pt1,dp;
quotientf ycur;
if ((unsigned int)ipt.x>=(unsigned int)isz.x || ipt.y<0)
return 0;
for(bInside=0; ipt.y<=isz.y && !bStop; ipt.y++)
for(i=g_BoolGrid[ipt.y*isz.x+ipt.x]; i<g_BoolGrid[ipt.y*isz.x+ipt.x+1]; i++) if (g_BoolHash[i]>>31^iobj) {
pt0 = ptsrc[g_BoolHash[i]&0x7FFFFFFF]; pt1 = ptsrc[(g_BoolHash[i]&0x7FFFFFFF)+1]; dp = pt1-pt0;
ycur.set((dp^pt0)+pt.x*dp.y, dp.x).fixsign();
if (isneg(fabs_tpl((pt0.x+pt1.x)-pt.x*2)-fabs_tpl(pt0.x-pt1.x)) & isneg(pt.y-ycur))
{ bInside -= sgn(dp.x); bStop=1; }
}
return isneg(-bInside);
}
int boolean2d(booltype type, vector2df *ptbuf1,int npt1, vector2df *ptbuf2,int npt2,int bClosed, vector2df *&ptres,int *&pidres)
{
vector2df *ptsrc[2] = { ptbuf1,ptbuf2 };
int npt[2] = { npt1,npt2 };
vector2df dp,dp1,ptmin[2],ptmax[2],sz,ptbox[2],ptint[2],pttest,rstep;
int iobj,i,j,idx,nsz,n,npttmp,nptres,ninters=0,istart,ix,iy,bInside,bPrevInside,idx_next,idx_prev,inext,inext1,iobj1;
vector2di ipt0,ipt1,irect[2],isz;
float t,ratioxy,ratioyx;
static int __bforce1=0,__bforce2=0;
//for(i=0;i<max(npt1,npt2);i++) g_BoolIdBuf[i]=0;
pidres = g_BoolIdBuf;
if (npt1<3 || __bforce2)
{ ptres = ptbuf2; return npt2&-(bClosed|__bforce2); }
if (npt2<2+bClosed || __bforce1)
{ ptres = ptbuf1; return npt1&-(bClosed|__bforce1); }
for(iobj=0;iobj<2;iobj++) {
ptmin[iobj] = ptmax[iobj] = ptsrc[iobj][0];
for(i=1;i<npt[iobj];i++) {
ptmin[iobj].x = min(ptmin[iobj].x,ptsrc[iobj][i].x); ptmin[iobj].y = min(ptmin[iobj].y,ptsrc[iobj][i].y);
ptmax[iobj].x = max(ptmax[iobj].x,ptsrc[iobj][i].x); ptmax[iobj].y = max(ptmax[iobj].y,ptsrc[iobj][i].y);
}
}
ptbox[0].x = max(ptmin[0].x,ptmin[1].x); ptbox[0].y = max(ptmin[0].y,ptmin[1].y);
ptbox[1].x = min(ptmax[0].x,ptmax[1].x); ptbox[1].y = min(ptmax[0].y,ptmax[1].y);
sz = ptbox[1]-ptbox[0];
sz.x += fabs_tpl(sz.y)*1E-5f; sz.y += fabs_tpl(sz.x)*1E-5f;
if (sz.x<fabs_tpl(sz.y)*5E-6f || sz.y<fabs_tpl(sz.x)*5E-6f)
return 0;
ptbox[0] -= sz*0.01f; ptbox[1] += sz*0.01f; sz = ptbox[1]-ptbox[0];
sz.x += fabs_tpl(sz.y)*1E-5f; sz.y += fabs_tpl(sz.x)*1E-5f;
i = (int)(sizeof(g_BoolGrid)/sizeof(g_BoolGrid[0])-1);
npttmp = min(npt[0]+npt[1]<<1, i);
ratioyx = max(min(sz.y/sz.x,(float)npttmp),1.0f);
ratioxy = max(min(sz.x/sz.y,(float)npttmp),1.0f);
isz.y = max(1,float2int(cry_sqrtf(npttmp*4*ratioyx+1)*0.5f-1.0f));
isz.x = max(1,float2int(isz.y*ratioxy-0.5f));
if (isz.x*(isz.y+1)>i) {
isz.y = min(isz.y,i); isz.x = i/(isz.y+1);
}
rstep.set(isz.x/sz.x, isz.y/sz.y);
nsz = isz.x*(isz.y+1);
if (nsz>=sizeof(g_BoolGrid)/sizeof(g_BoolGrid[0])-1)
return 0;
npt[1] -= bClosed^1;
for(i=0;i<=nsz;i++) g_BoolGrid[i] = 0;
for(iobj=0;iobj<2;iobj++) { // calculate number of elements in each cell
for(get_cell(ptsrc[iobj][i=0]-ptbox[0],rstep,ipt0); i<npt[iobj]; i++) {
get_cell(ptsrc[iobj][i+1]-ptbox[0],rstep,ipt1); get_rect(ipt0,ipt1,irect,isz);
for(ix=irect[0].x;ix<=irect[1].x;ix++) for(iy=irect[0].y;iy<=irect[1].y;iy++)
g_BoolGrid[iy*isz.x+ix]++;
ipt0 = ipt1;
}
}
for(i=1;i<=nsz;i++) g_BoolGrid[i]+=g_BoolGrid[i-1];
if (g_BoolGrid[nsz-1]>(int)(sizeof(g_BoolHash)/sizeof(g_BoolHash[0])))
return 0;
for(iobj=0;iobj<2;iobj++) { // put each line segment into the corresponding hash cell(s)
for(get_cell(ptsrc[iobj][i=0]-ptbox[0],rstep,ipt0); i<npt[iobj]; i++) {
get_cell(ptsrc[iobj][i+1]-ptbox[0],rstep,ipt1); get_rect(ipt0,ipt1,irect,isz);
for(ix=irect[0].x;ix<=irect[1].x;ix++) for(iy=irect[0].y;iy<=irect[1].y;iy++)
g_BoolHash[--g_BoolGrid[iy*isz.x+ix]] = iobj<<31 | i;
ipt0 = ipt1;
}
}
// select iobj which is likely to have shorter edges
if (bClosed)
iobj = isneg((ptmax[1].x-ptmin[1].x+ptmax[1].y-ptmin[1].y)*npt[0] -
(ptmax[0].x-ptmin[0].x+ptmax[0].y-ptmin[0].y)*npt[1]);
else iobj = 1;
// build list of intersections by traversing iobj
if (!bClosed) {
g_BoolInters[0].pt = ptsrc[1][0];
g_BoolInters[0].iedge[0] = -1; g_BoolInters[0].iedge[1] = 0;
ninters = 1;
}
for(get_cell(ptsrc[iobj][0]-ptbox[0],rstep,ipt0),i=0; i<npt[iobj]; i++) {
get_cell(ptsrc[iobj][i+1]-ptbox[0],rstep,ipt1); get_rect(ipt0,ipt1,irect,isz);
istart = ninters;
for(ix=irect[0].x;ix<=irect[1].x;ix++) for(iy=irect[0].y;iy<=irect[1].y;iy++)
for(j=g_BoolGrid[iy*isz.x+ix]; j<g_BoolGrid[iy*isz.x+ix+1]; j++) if (g_BoolHash[j]>>31^iobj) {
for(n=line_seg_inters(ptsrc[iobj]+i, ptsrc[iobj^1]+(g_BoolHash[j]&0x7FFFFFFF), ptint)-1; n>=0; n--) {
dp = ptsrc[iobj][i+1]-ptsrc[iobj][i]; t = (ptint[n]-ptsrc[iobj][i])*dp;
for(idx=istart; idx<ninters && fabs_tpl((g_BoolInters[idx].pt-ptsrc[iobj][i])*dp-t)>t*1E-7f; idx++);
if (idx<ninters)
continue; // ignore possible intersections with the same line found in different cell
if (ninters==sizeof(g_BoolInters)/sizeof(g_BoolInters[0])-1)
return 0;
for(idx=ninters-1; idx>=istart && (g_BoolInters[idx].pt-ptsrc[iobj][i])*dp>t; idx--)
g_BoolInters[idx+1] = g_BoolInters[idx];
g_BoolInters[idx+1].pt = ptint[n];
g_BoolInters[idx+1].iedge[iobj] = i;
g_BoolInters[idx+1].iedge[iobj^1] = g_BoolHash[j]&0x7FFFFFFF;
ninters++;
}
}
ipt0 = ipt1;
}
if (!bClosed) {
if (ninters==sizeof(g_BoolInters)/sizeof(g_BoolInters[0])-1)
return 0;
g_BoolInters[ninters].pt = ptsrc[1][npt[1]];
g_BoolInters[ninters].iedge[0] = -1; g_BoolInters[ninters].iedge[1] = npt[1];
g_BoolInters[ninters+1] = g_BoolInters[ninters]; ninters++;
} else
g_BoolInters[ninters] = g_BoolInters[0];
nptres = 0; ptres = g_BoolPtBuf;
// if there were no intersections, return the object that is inside the other
if (ninters-(bClosed^1)*2==0) {
get_cell(ptsrc[iobj][0]-ptbox[0],rstep,ipt0);
bInside = check_if_inside(iobj,ipt0,isz,ptsrc[iobj^1],ptsrc[iobj][0]);
npt[1] += bClosed^1;
if (bClosed) // assume that objects cannot have empty intersection area, thus if iobj is not inside iobj^1, ibj1^1 should be inside iobj
iobj ^= bInside^1;
ptres = ptsrc[iobj];
for(nptres=0;nptres<npt[iobj];nptres++)
g_BoolIdBuf[nptres] = nptres+1<<iobj*16;
return nptres & -(bClosed|bInside);
}
npt[1] += bClosed^1; // compensate for 1 subtracted earlier
// build boolean intersection by at each intersection point selecting the stripe that is more 'inward' than the other one
for(idx=bPrevInside=0; idx<ninters; idx++) {
idx_next = idx+1; //& ~(ninters-2-idx>>31);
idx_prev = idx-1; idx_prev = idx_prev&~(idx_prev>>31) | ninters-1&idx_prev>>31;
i = g_BoolInters[idx].iedge[iobj]; inext = i+1 & i+1-npt[iobj]>>31;
dp = ptsrc[iobj][inext]-ptsrc[iobj][i];
inext1 = min(inext+1,npt[iobj]-1) & (i+1-npt[iobj]>>31 | ~-bClosed);
j = g_BoolInters[idx].iedge[iobj^1];
if (j>=0) {
dp1 = ptsrc[iobj^1][j+1 & j+1-npt[iobj^1]>>31]-ptsrc[iobj^1][j];
bInside = isneg(dp^dp1);
} else {
pttest = g_BoolInters[idx].pt;
get_cell(pttest-ptbox[0],rstep,ipt0);
bInside = check_if_inside(iobj,ipt0,isz,ptsrc[iobj^1],pttest);
}
/*
// build boolean intersection by selecting fragments (stripes between 2 intersection points) of the object that is inside another object
// cannot just switch "inside" state at each intersection, since it's less stable in case of degenerate contacts
// find some representative point for this fragment
if (g_BoolInters[idx_next].iedge[iobj]==i && (g_BoolInters[idx_next].pt-ptsrc[iobj][i])*dp>(g_BoolInters[idx].pt-ptsrc[iobj][i])*dp)
pttest = (g_BoolInters[idx].pt+g_BoolInters[idx_next].pt)*0.5f; // next intersection lies on the same edge
else if ((g_BoolInters[idx].pt-ptsrc[iobj][i])*dp < dp.len2()*0.95f*0.95f)
pttest = (g_BoolInters[idx].pt+ptsrc[iobj][inext1])*0.5f; // this intersection is not too close to the edge end
else if (g_BoolInters[idx_next].iedge[iobj]==inext)
pttest = (ptsrc[iobj][inext]+g_BoolInters[idx_next].pt)*0.5f; // next intersection lies on the next edge
else
pttest = (ptsrc[iobj][inext]+ptsrc[iobj][inext1])*0.5f;
// check if a ray upwards from pttest first hits right-to-left edge of iobj^1, in this case we are inside
get_cell(pttest-ptbox[0],rstep,ipt0);
bInside = check_if_inside(iobj,ipt0,isz,ptsrc[iobj^1],pttest);*/
iobj1 = iobj^bInside^1;
if (bInside | bPrevInside | bClosed) {
g_BoolPtBuf[nptres] = g_BoolInters[idx].pt;
g_BoolIdBuf[nptres++] = g_BoolInters[idx].iedge[1]+1<<16 | g_BoolInters[idx].iedge[0]+1;
if (nptres>=(int)(sizeof(g_BoolPtBuf)/sizeof(g_BoolPtBuf[0])))
return nptres;
}
if (bInside | bClosed) {
i = g_BoolInters[idx].iedge[iobj1];
inext = i+1 & ~(npt[iobj1]-2-i>>31);
dp = ptsrc[iobj1][inext]-ptsrc[iobj1][i];
bool bForceFirstStep = i==g_BoolInters[idx_next].iedge[iobj1] &&
(g_BoolInters[idx].pt-ptsrc[iobj1][i])*dp > (g_BoolInters[idx_next].pt-ptsrc[iobj1][i])*dp;
for(; bForceFirstStep ||
i!=g_BoolInters[idx_next].iedge[iobj1] && (iobj1==iobj || i!=g_BoolInters[idx_prev].iedge[iobj1]);
i=i+1&~(npt[iobj1]-2-i>>31))
{
g_BoolPtBuf[nptres] = ptsrc[iobj1][i+1];
g_BoolIdBuf[nptres++] = i+2<<iobj1*16;
if (nptres>=(int)(sizeof(g_BoolPtBuf)/sizeof(g_BoolPtBuf[0])))
return nptres;
bForceFirstStep = false;
}
}
bPrevInside = bInside;
}
return nptres;
}

485
CryPhysics/boxgeom.cpp Normal file
View File

@@ -0,0 +1,485 @@
#include "stdafx.h"
#include "utils.h"
#include "primitives.h"
#include "overlapchecks.h"
#include "unprojectionchecks.h"
#include "bvtree.h"
#include "singleboxtree.h"
#include "geometry.h"
#include "trimesh.h"
#include "boxgeom.h"
vector2df g_BoxCont[8];
int g_BoxVtxId[8],g_BoxEdgeId[8];
CBoxGeom* CBoxGeom::CreateBox(box *pbox)
{
m_box.center = pbox->center;
m_box.size = pbox->size;
m_box.Basis = pbox->Basis;
m_box.bOriented = m_box.Basis.IsIdentity()^1;
m_Tree.SetBox(&m_box);
m_Tree.Build(this);
m_minVtxDist = (m_box.size.x+m_box.size.y+m_box.size.z)*1E-4f;
return this;
}
int CBoxGeom::CalcPhysicalProperties(phys_geometry *pgeom)
{
pgeom->pGeom = this;
pgeom->origin = m_box.center;
if (!m_box.bOriented)
pgeom->q.SetIdentity();
else
pgeom->q = quaternionf(m_box.Basis.T());
pgeom->V = m_box.size.volume()*8;
pgeom->Ibody.Set(sqr(m_box.size.y)+sqr(m_box.size.z), sqr(m_box.size.x)+sqr(m_box.size.z),
sqr(m_box.size.x)+sqr(m_box.size.y)) *= pgeom->V*(1.0/3);
return 1;
}
int CBoxGeom::PointInsideStatus(const vectorf &pt)
{
vectorf ptloc = pt-m_box.center;
if (m_box.bOriented)
ptloc = m_box.Basis*ptloc;
return isneg(fabsf(ptloc.x)-m_box.size.x) & isneg(fabsf(ptloc.y)-m_box.size.y) & isneg(fabsf(ptloc.z)-m_box.size.z);
}
int CBoxGeom::PrepareForIntersectionTest(geometry_under_test *pGTest, CGeometry *pCollider,geometry_under_test *pGTestColl, bool bKeepPrevContacts)
{
static short g_BoxIdBuf[3];
static surface_desc g_BoxSurfaceBuf[3];
static edge_desc g_BoxEdgeBuf[3];
pGTest->pGeometry = this;
pGTest->pBVtree = &m_Tree;
m_Tree.PrepareForIntersectionTest(pGTest);
pGTest->primbuf = pGTest->primbuf1 = g_BoxBuf+g_BoxBufPos++;
pGTest->szprimbuf = 1;
pGTest->typeprim = box::type;
pGTest->szprim = sizeof(box);
pGTest->idbuf = g_BoxIdBuf;
pGTest->surfaces = g_BoxSurfaceBuf;
pGTest->edges = g_BoxEdgeBuf;
pGTest->minAreaEdge = 0;
return 1;
}
void CBoxGeom::PrepareBox(box *pbox, geometry_under_test *pGTest)
{
pbox->center = pGTest->R*m_box.center*pGTest->scale + pGTest->offset;
if (!m_box.bOriented) pbox->Basis = pGTest->R.T();
else pbox->Basis = m_box.Basis*pGTest->R.T();
pbox->bOriented = 1;
pbox->size = m_box.size*pGTest->scale;
}
int CBoxGeom::PreparePrimitive(geom_world_data *pgwd, primitive *&pprim)
{
box *pbox = g_BoxBuf+g_BoxBufPos;
g_BoxBufPos = g_BoxBufPos+1 & sizeof(g_BoxBuf)/sizeof(g_BoxBuf[0])-1;
pbox->center = pgwd->R*m_box.center*pgwd->scale + pgwd->offset;
if (!m_box.bOriented) pbox->Basis = pgwd->R.T();
else pbox->Basis = m_box.Basis*pgwd->R.T();
pbox->bOriented = 1;
pbox->size = m_box.size*pgwd->scale;
pprim = pbox;
return box::type;
}
int CBoxGeom::GetFeature(int iPrim,int iFeature, vectorf *pt)
{
int i,sg,ix,iy,iz;
switch (iFeature & 0x60) {
case 0: // vertex
pt->x=m_box.size.x*((iFeature<<1&2)-1); pt->y=m_box.size.y*((iFeature&2)-1);
pt->z=m_box.size.z*((iFeature>>1&2)-1); pt[0] = pt[0]*m_box.Basis+m_box.center; return 1;
case 0x20: // edge
iz = iFeature>>2&3; ix = inc_mod3[iz]; iy = dec_mod3[iz];
pt[0][ix]=pt[1][ix]=m_box.size[ix]*((iFeature<<1&2)-1); pt[0][iy]=pt[1][iy]=m_box.size[iy]*((iFeature&2)-1);
pt[0][iz]=-m_box.size[iz]; pt[1][iz]=m_box.size[iz];
pt[0] = pt[0]*m_box.Basis+m_box.center; pt[1] = pt[1]*m_box.Basis+m_box.center; return 2;
case 0x40: // face
iz = iFeature>>1&3; ix = inc_mod3[iz]; iy = dec_mod3[iz]; sg = (iFeature<<1&2)-1;
for(i=0;i<4;i++) {
pt[i^(sg&3)][ix] = m_box.size[ix]*(1-((i^i<<1)&2));
pt[i^(sg&3)][iy] = m_box.size[iy]*(1-(i&2));
pt[i^(sg&3)][iz] = m_box.size[iz]*sg;
pt[i^(sg&3)] = pt[i^(sg&3)]*m_box.Basis+m_box.center;
}
return 4;
}
return 0;
}
int CBoxGeom::GetPrimitiveList(int iStart,int nPrims, int typeCollider,primitive *pCollider,int bColliderLocal,
geometry_under_test *pGTest,geometry_under_test *pGTestOp, primitive *pRes,short *pResId)
{
PrepareBox((box*)pRes, pGTest);
box *pbox = (box*)pRes;
float szmax=max(max(pbox->size.x,pbox->size.y),pbox->size.z), szmin=min(min(pbox->size.x,pbox->size.y),pbox->size.z);
if (pGTestOp->ptOutsidePivot.x<1E10 && szmin*8.0f<szmax) {
int iz=idxmin3((float*)&pbox->size), ix=inc_mod3[iz], iy=dec_mod3[iz];
vectorf ptloc = pbox->Basis*(pGTestOp->ptOutsidePivot-pbox->center);
if (ptloc[ix]<pbox->size[ix] && ptloc[iy]<pbox->size[iy]) {
pbox->center -= pbox->Basis.GetRow(iz)*(sgnnz(ptloc[iz])*szmax);
pbox->size[iz] += szmax;
}
}
pGTest->bTransformUpdated = 0; *pResId = -1;
return 1;
}
int CBoxGeom::GetUnprojectionCandidates(int iop,const contact *pcontact, primitive *&pprim,int *&piFeature, geometry_under_test *pGTest)
{
if (pGTest->bTransformUpdated) {
pprim = pGTest->primbuf1;
PrepareBox((box*)pprim, pGTest);
}
box *pbox = (box*)pprim;
pGTest->idbuf[0] = -1;
int iFeature = pcontact->iFeature[iop],ix,iy,iz;
vectorf ptloc = pbox->Basis*(pcontact->pt-pbox->center);
if ((iFeature&0xE0)==0x40) { // check if the point on the face is close to some edge
iz=iFeature>>1 & 3; ix=inc_mod3[iz]; iy=dec_mod3[iz];
if (fabsf(ptloc[ix]-pbox->size[ix]) < pbox->size[ix]*0.001f)
iFeature = 0x20 | ix<<2 | (iFeature&1<<1) | sgnnz(ptloc[iy])+1>>1;
else if (fabsf(ptloc[iy]-pbox->size[iy]) < pbox->size[iy]*0.001f)
iFeature = 0x20 | iy<<2 | sgnnz(ptloc[ix])+1 | iFeature&1;
}
if ((iFeature&0xE0)==0x20) { // check if the point on the edge is close to one of its ends
iz = iFeature>>2 & 3; ix=inc_mod3[iz]; iy=dec_mod3[iz];
if (fabsf(ptloc[iz]-pbox->size[iz])<pbox->size[iz]*0.001f)
iFeature = (iFeature&1)<<ix | (iFeature>>1&1)<<iy | (sgnnz(ptloc[iz])+1>>1)<<iz;
}
if ((iFeature&0xE0)==0x40) {
iz = iFeature>>1 & 3;
pGTest->surfaces[0].n = pbox->Basis.GetRow(iz)*((iFeature<<1&2)-1);
pGTest->surfaces[0].idx = 0;
pGTest->surfaces[0].iFeature = iFeature;
pGTest->nSurfaces = 1;
pGTest->nEdges = 0;
} else if ((iFeature&0xE0)==0x20) {
iz = iFeature>>2 & 3; ix=inc_mod3[iz]; iy=dec_mod3[iz];
pGTest->surfaces[0].idx = pGTest->surfaces[1].idx = 0;
pGTest->edges[0].n[0] = -(pGTest->surfaces[0].n = pbox->Basis.GetRow(ix)*((iFeature<<1&2)-1));
pGTest->edges[0].n[1] = -(pGTest->surfaces[1].n = pbox->Basis.GetRow(iy)*((iFeature&2)-1));
pGTest->surfaces[0].iFeature = 0x40 | ix<<1 | iFeature&1;
pGTest->surfaces[1].iFeature = 0x40 | iy<<1 | iFeature>>1&1;
pGTest->nSurfaces = 2;
pGTest->edges[0].dir = pbox->Basis.GetRow(iz);
pGTest->edges[0].idx = 0;
pGTest->edges[0].iFeature = iFeature;
pGTest->nEdges = 1;
} else {
for(iz=0;iz<3;iz++) {
pGTest->surfaces[iz].idx = pGTest->edges[iz].idx = 0;
pGTest->edges[iz].dir = pGTest->surfaces[iz].n = pbox->Basis.GetRow(iz)*(((iFeature>>iz)<<1&2)-1);
pGTest->surfaces[iz].iFeature = 0x40 | iz<<1 | iFeature>>iz&1;
ix = inc_mod3[iz]; iy = dec_mod3[iz];
pGTest->edges[iz].n[0] = pbox->Basis.GetRow(ix)*(1-((iFeature>>ix)<<1&2));
pGTest->edges[iz].n[1] = pbox->Basis.GetRow(iy)*(1-((iFeature>>iy)<<1&2));
pGTest->edges[iz].iFeature = 0x20 | iz<<2 | (iFeature>>iy&1)<<1 | iFeature>>ix&1;
}
pGTest->nSurfaces = pGTest->nEdges = 3;
}
return 1;
}
int CBoxGeom::PreparePolygon(coord_plane *psurface, int iPrim,int iFeature, geometry_under_test *pGTest, vector2df *&ptbuf,
int *&pVtxIdBuf,int *&pEdgeIdBuf)
{
int i,sg;
vectorf size,center,pt;
matrix3x3f R;
if (!m_box.bOriented) R = pGTest->R;
else R = pGTest->R*m_box.Basis.T();
Vec3_tpl<int> ic;
size = m_box.size*pGTest->scale;
ic.z = iFeature>>1&3; ic.x = inc_mod3[ic.z]; ic.y = dec_mod3[ic.z]; sg = (iFeature<<1&2)-1;
center = pGTest->R*m_box.center*pGTest->scale + pGTest->offset + R.GetColumn(ic.z)*(size[ic.z]*sg);
if (psurface->n.len2()==0) {
psurface->n = R.GetColumn(ic.z)*sg;
psurface->axes[0] = R.GetColumn(ic.x);
psurface->axes[1] = R.GetColumn(ic.y)*sg;
psurface->origin = center; sg &= 3;
} else
sg = -isneg(psurface->n*R.GetColumn(ic.z))&3;
//sg = sgnnz(psurface->n*R.GetColumn(ic.z))>>31 & 3;
center -= psurface->origin;
for(i=0;i<4;i++) {
pt[ic.x] = size[ic.x]*(1-((i^i<<1)&2));
pt[ic.y] = size[ic.y]*(1-(i&2));
pt[ic.z] = 0;
pt = center+R*pt;
g_BoxCont[i^sg].set(pt*psurface->axes[0],pt*psurface->axes[1]);
g_BoxEdgeId[(i^sg)-(sg&1) & 3] = 0x20 | ic[i&1]<<2 | (iFeature&1)<<(i&1) | (((i^i>>1)&1)^1)<<((i&1)^1);
g_BoxVtxId[i^sg] = (iFeature&1)<<ic.z | ((i^i>>1)&1)<<ic.x | (i>>1&1)<<ic.y;
}
g_BoxCont[4] = g_BoxCont[0];
ptbuf = g_BoxCont; pVtxIdBuf = g_BoxVtxId; pEdgeIdBuf = g_BoxEdgeId;
return 4;
}
int CBoxGeom::PreparePolyline(coord_plane *psurface, int iPrim,int iFeature, geometry_under_test *pGTest, vector2df *&ptbuf,
int *&pVtxIdBuf,int *&pEdgeIdBuf)
{
int ix,iy,iz;
vectorf pt,offs;
matrix3x3f R;
if (!m_box.bOriented) R = pGTest->R;
else R = pGTest->R*m_box.Basis.T();
iz=iFeature>>2&3; ix=inc_mod3[iz]; iy=dec_mod3[iz];
offs[ix] = m_box.size[ix]*((iFeature<<1&2)-1);
offs[iy] = m_box.size[iy]*((iFeature&2)-1);
offs[iz] = -m_box.size[iz];
pt = (pGTest->R*m_box.center+R*offs)*pGTest->scale + pGTest->offset - psurface->origin;
g_BoxCont[0].set(pt*psurface->axes[0],pt*psurface->axes[1]);
offs[ix]=offs[iy] = 0; offs[iz] = m_box.size[iz]*2;
pt += R*offs*pGTest->scale;
g_BoxCont[1].set(pt*psurface->axes[0],pt*psurface->axes[1]);
g_BoxEdgeId[0] = g_BoxEdgeId[1] = iFeature;
g_BoxVtxId[0] = (iFeature&1)<<ix | (iFeature>>1&1)<<iy;
g_BoxVtxId[1] = g_BoxVtxId[0] | 1<<iz;
g_BoxCont[2] = g_BoxCont[0];
ptbuf = g_BoxCont; pVtxIdBuf = g_BoxVtxId; pEdgeIdBuf = g_BoxEdgeId;
return 2;
}
int CBoxGeom::FindClosestPoint(geom_world_data *pgwd, int &iPrim,int &iFeature, const vectorf &ptdst0,const vectorf &ptdst1,
vectorf *ptres, int nMaxIters)
{
int i,iz,nFacesi,nFaces[2],bLine;
vectori sg[2],idir[2],sgi,idiri;
vectorf ptloc[2],size,diri,dir[2],ptdst[2]={ ptdst0,ptdst1 };
ptres[0].Set(1E10f,1E10f,1E10f);
ptres[1] = ptdst0;
ptloc[0] = (ptdst0-pgwd->offset)*pgwd->R-m_box.center*pgwd->scale;
if (m_box.bOriented)
ptloc[0] = m_box.Basis*ptloc[0];
size = m_box.size*pgwd->scale;
iPrim = 0;
if (bLine = isneg(size.x*1E-5f-(ptdst0-ptdst1).len2())) {
int ix,iy,iedge,ivtx;
vectorf ptbox,n;
float n2,dir2,t0,t1;
ptloc[1] = (ptdst1-pgwd->offset)*pgwd->R-m_box.center*pgwd->scale;
if (m_box.bOriented)
ptloc[1] = m_box.Basis*ptloc[1];
diri = ptloc[1]-ptloc[0]; dir2 = diri.len2();
for(iz=0;iz<3;iz++) {
n = cross_with_ort(diri,iz); n2 = n.len2();
ptbox[iz] = 0; ix = inc_mod3[iz]; iy = dec_mod3[iz];
for(iedge=0;iedge<4;iedge++) {
ptbox[ix] = size[ix]*((iedge&1)*2-1); ptbox[iy] = size[iy]*((iedge&2)-1);
t0 = cross_with_ort(ptbox-ptloc[0],iz)*n;
t1 = (ptbox-ptloc[0]^diri)*n;
if (inrange(t0, (float)0,n2) & isneg(fabs_tpl(t1)-n2*size[iz])) {
iFeature = 0x20|iz<<2|iedge; n2 = 1.0f/n2;
ptbox[iz] = t1*n2;
ptres[0] = pgwd->R*(ptbox*m_box.Basis+m_box.center*pgwd->scale)+pgwd->offset;
ptres[1] = pgwd->R*((ptloc[0]+diri*(t0*n2))*m_box.Basis+m_box.center*pgwd->scale)+pgwd->offset;
return 1;
}
}
}
for(ivtx=0;ivtx<8;ivtx++) {
ptbox.x = size.x*((ivtx&1)*2-1); ptbox.y = size.y*((ivtx&2)-1); ptbox.z = size.z*((ivtx>>1&2)-1);;
if (inrange(t0=(ptbox-ptloc[0])*diri,(float)0,dir2)) {
iFeature = ivtx;
ptres[0] = pgwd->R*(ptbox*m_box.Basis+m_box.center*pgwd->scale)+pgwd->offset;
ptres[1] = pgwd->R*((ptloc[0]+diri*(t0/dir2))*m_box.Basis+m_box.center*pgwd->scale)+pgwd->offset;
return 1;
}
}
}
dir[1].zero(); nFaces[1]=0;
for(i=0;i<=bLine;i++) {
for(iz=nFacesi=0;iz<3;iz++) {
sgi[nFacesi] = sgnnz(ptloc[i][iz]);
diri[iz] = max(0.0f,fabsf(ptloc[i][iz])-size[iz])*-sgi[nFacesi];
idiri[nFacesi] = iz; nFacesi += isneg(1E-4f-fabsf(diri[iz]));
}
nFaces[i]=nFacesi; sg[i]=sgi;
dir[i]=diri; idir[i]=idiri;
}
if (nFaces[0]+nFaces[1]==0)
return -1;
i = isneg(dir[1].len2()-dir[0].len2()) & isneg(-nFaces[1]);
if (nFaces[i]==1)
iFeature = 0x40 | idir[i][0]<<1 | sg[i][0]+1>>1;
else if (nFaces[i]==2) {
iz = 3-idir[i][0]-idir[i][1];
iFeature = 0x20 | iz<<2 | (sg[i][0]+1>>1)<<(iz&1) | sg[i][1]+1>>(iz&1);
} else
iFeature = sg[i][2]+1<<1 | sg[i][1]+1 | sg[i][0]+1>>1;
ptloc[i] += dir[i];
if (m_box.bOriented)
ptloc[i] = ptloc[i]*m_box.Basis;
ptres[0] = pgwd->R*(ptloc[i]+m_box.center*pgwd->scale)+pgwd->offset;
ptres[1] = ptdst[i];
return 1;
}
void CBoxGeom::BuildTriMesh(CTriMesh &mesh)
{
static vectorf normals[12],vtx[8];
static int idx[36] = { 0,4,6, 6,2,0, 1,3,7, 7,5,1, 0,1,5, 5,4,0, 2,6,7, 7,3,2, 0,2,3, 3,1,0, 4,5,7, 7,6,4 };
mesh.m_nTris = 12;
mesh.m_nVertices = 8;
mesh.m_pNormals = normals;
mesh.m_pVertices = vtx;
mesh.m_pIndices = idx;
mesh.m_flags = 4;
int i; for(i=0;i<8;i++) {
vtx[i].Set(m_box.size.x*((i<<1&2)-1),m_box.size.y*((i&2)-1),m_box.size.z*((i>>1&2)-1));
if (m_box.bOriented) vtx[i] = vtx[i]*m_box.Basis;
vtx[i] += m_box.center;
}
for(i=0;i<6;i++) {
normals[i*2].Set(0,0,0); normals[i*2][i>>1] = ((i&1)<<1)-1;
if (m_box.bOriented) normals[i*2] = normals[i*2]*m_box.Basis;
normals[i*2+1] = normals[i*2];
}
}
int CBoxGeom::UnprojectSphere(vectorf center,float r,float rsep, contact *pcontact)
{
sphere sph;
sph.center = center;
sph.r = rsep;
if (!box_sphere_overlap_check(&m_box,&sph))
return 0;
unprojection_mode umode;
umode.dir.Set(0,0,0);
box_sphere_lin_unprojection(&umode,&m_box,-1,&sph,-1,pcontact,0);
pcontact->pt -= umode.dir*pcontact->t;
return 1;
}
void CBoxGeom::CalcVolumetricPressure(geom_world_data *gwd, const vectorf &epicenter,float k,float rmin,
const vectorf &centerOfMass, vectorf &P,vectorf &L)
{
CTriMesh mesh; BuildTriMesh(mesh);
mesh.CalcVolumetricPressure(gwd,epicenter,k,rmin,centerOfMass,P,L);
}
float CBoxGeom::CalculateBuoyancy(const plane *pplane, const geom_world_data *pgwd, vectorf &massCenter)
{
CTriMesh mesh; BuildTriMesh(mesh);
return mesh.CalculateBuoyancy(pplane,pgwd,massCenter);
}
void CBoxGeom::CalculateMediumResistance(const plane *pplane, const geom_world_data *pgwd, vectorf &dPres,vectorf &dLres)
{
int i,j,ix,iy,iz;
vectorf pt[4],n, size=m_box.size*pgwd->scale, offset=pgwd->R*m_box.center*pgwd->scale+pgwd->offset;
matrix3x3f R;
if (!m_box.bOriented) R = pgwd->R;
else R = pgwd->R*m_box.Basis.T();
dPres.Set(0,0,0); dLres.zero();
for(i=0;i<6;i++) {
iz=i>>1; ix=inc_mod3[iz]; iy=dec_mod3[iz];
n.Set(0,0,0); n[iz] = ((i<<1&2)-1);
for(j=0;j<4;j++) {
pt[j][ix] = size[ix]*(1-((j^j<<1)&2));
pt[j][iy] = size[iy]*((j&2^i<<1&2)-1);
pt[j][iz] = size[iz]*n[iz];
pt[j] = R*pt[j]+offset;
}
CalcMediumResistance(pt,4,R*n, *pplane, pgwd->v,pgwd->w,pgwd->centerOfMass, dPres,dLres);
}
}
int CBoxGeom::DrawToOcclusionCubemap(const geom_world_data *pgwd, int iStartPrim,int nPrims, int iPass, int *pGrid[6],int nRes,
float rmin,float rmax,float zscale)
{
int i,j,ix,iy,iz;
vectorf pt[4],n, size=m_box.size*pgwd->scale, offset=pgwd->R*m_box.center*pgwd->scale+pgwd->offset;;
matrix3x3f R;
if (!m_box.bOriented) R = pgwd->R;
else R = pgwd->R*m_box.Basis.T();
for(i=0;i<6;i++) {
iz=i>>1; ix=inc_mod3[iz]; iy=dec_mod3[iz];
n.Set(0,0,0); n[iz] = (((i&1)<<1)-1);
for(j=0;j<4;j++) {
pt[j][ix] = size[ix]*(1-((j^j<<1)&2));
pt[j][iy] = size[iy]*((j&2^i<<1&2)-1);
pt[j][iz] = size[iz]*n[iz];
pt[j] = R*pt[j]+offset;
}
RasterizePolygonIntoCubemap(pt,4, iPass, pGrid,nRes, rmin,rmax,zscale);
}
return 1;
}
void CBoxGeom::DrawWireframe(void (*DrawLineFunc)(float*,float*), geom_world_data *pgwd, int iLevel)
{
int i,j;
vectorf pt[8], size=m_box.size*pgwd->scale, offset=pgwd->R*m_box.center*pgwd->scale+pgwd->offset;
matrix3x3f R;
if (!m_box.bOriented) R = pgwd->R;
else R = pgwd->R*m_box.Basis.T();
for(i=0;i<8;i++)
pt[i] = R*vectorf(size.x*((i<<1&2)-1),size.y*((i&2)-1),size.z*((i>>1&2)-1))+offset;
for(i=0;i<8;i++) for(j=0;j<3;j++) if (i&1<<j)
DrawLineFunc(pt[i],pt[i^1<<j]);
}
void CBoxGeom::GetMemoryStatistics(ICrySizer *pSizer)
{
pSizer->AddObject(this, sizeof(CBoxGeom));
}
void CBoxGeom::Save(CMemStream &stm)
{
stm.Write(m_box);
m_Tree.Save(stm);
}
void CBoxGeom::Load(CMemStream &stm)
{
stm.Read(m_box);
m_Tree.Load(stm,this);
}

54
CryPhysics/boxgeom.h Normal file
View File

@@ -0,0 +1,54 @@
#ifndef boxgeom_h
#define boxgeom_h
#pragma once
class CTriMesh;
class CBoxGeom : public CPrimitive {
public:
CBoxGeom() { m_iCollPriority = 3; m_minVtxDist = 0; }
CBoxGeom* CreateBox(box *pcyl);
void PrepareBox(box *pbox, geometry_under_test *pGTest);
virtual int PreparePrimitive(geom_world_data *pgwd,primitive *&pprim);
virtual int GetType() { return GEOM_BOX; }
virtual void GetBBox(box *pbox) { m_Tree.GetBBox(pbox); }
virtual int CalcPhysicalProperties(phys_geometry *pgeom);
virtual int FindClosestPoint(geom_world_data *pgwd, int &iPrim,int &iFeature, const vectorf &ptdst0,const vectorf &ptdst1,
vectorf *ptres, int nMaxIters);
virtual int PointInsideStatus(const vectorf &pt);
virtual void CalcVolumetricPressure(geom_world_data *gwd, const vectorf &epicenter,float k,float rmin,
const vectorf &centerOfMass, vectorf &P,vectorf &L);
virtual float CalculateBuoyancy(const plane *pplane, const geom_world_data *pgwd, vectorf &massCenter);
virtual void CalculateMediumResistance(const plane *pplane, const geom_world_data *pgwd, vectorf &dPres,vectorf &dLres);
virtual int DrawToOcclusionCubemap(const geom_world_data *pgwd, int iStartPrim,int nPrims, int iPass, int *pGrid[6],int nRes,
float rmin,float rmax,float zscale);
virtual CBVTree *GetBVTree() { return &m_Tree; }
virtual void DrawWireframe(void (*DrawLineFunc)(float*,float*), geom_world_data *gwd, int iLevel);
virtual int GetPrimitive(int iPrim, primitive *pprim) { *(box*)pprim = m_box; return sizeof(box); }
virtual int GetFeature(int iPrim,int iFeature, vectorf *pt);
virtual int UnprojectSphere(vectorf center,float r,float rsep, contact *pcontact);
virtual int PrepareForIntersectionTest(geometry_under_test *pGTest, CGeometry *pCollider,geometry_under_test *pGTestColl, bool bKeepPrevContacts=false);
virtual int GetPrimitiveList(int iStart,int nPrims, int typeCollider,primitive *pCollider,int bColliderLocal,
geometry_under_test *pGTest,geometry_under_test *pGTestOp, primitive *pRes,short *pResId);
virtual int GetUnprojectionCandidates(int iop,const contact *pcontact, primitive *&pprim,int *&piFeature, geometry_under_test *pGTest);
virtual int PreparePolygon(coord_plane *psurface, int iPrim,int iFeature, geometry_under_test *pGTest, vector2df *&ptbuf,
int *&pVtxIdBuf,int *&pEdgeIdBuf);
virtual int PreparePolyline(coord_plane *psurface, int iPrim,int iFeature, geometry_under_test *pGTest, vector2df *&ptbuf,
int *&pVtxIdBuf,int *&pEdgeIdBuf);
virtual void GetMemoryStatistics(ICrySizer *pSizer);
virtual void Save(CMemStream &stm);
virtual void Load(CMemStream &stm);
void BuildTriMesh(CTriMesh &mesh);
box m_box;
CSingleBoxTree m_Tree;
};
#endif

142
CryPhysics/bvtree.h Normal file
View File

@@ -0,0 +1,142 @@
#ifndef bvtree_h
#define bvtree_h
extern indexed_triangle g_IdxTriBuf[256];
extern int g_IdxTriBufPos;
extern cylinder g_CylBuf[2];
extern int g_CylBufPos;
extern sphere g_SphBuf[2];
extern int g_SphBufPos;
extern box g_BoxBuf[2];
extern int g_BoxBufPos;
////////////////////////// bounding volumes ////////////////////////
struct BV {
int type;
int iNode;
operator primitive*() { return (primitive*)((char*)this+sizeof(type)+sizeof(iNode)); }
};
struct BBox : BV {
box abox;
};
extern BBox g_BBoxBuf[128];
extern int g_BBoxBufPos;
struct BVheightfield : BV {
heightfield hf;
};
struct BVray : BV {
ray aray;
};
inline void ResetGlobalPrimsBuffers()
{
g_BBoxBufPos = 0;
g_IdxTriBufPos = 0;
g_CylBufPos = 0;
g_BoxBufPos = 0;
g_SphBufPos = 0;
}
class CGeometry;
class CBVTree;
struct surface_desc {
vectorf n;
int idx;
int iFeature;
};
struct edge_desc {
vectorf dir;
vectorf n[2];
int idx;
int iFeature;
};
struct geometry_under_test {
CGeometry *pGeometry;
CBVTree *pBVtree;
int *pUsedNodesMap;
int *pUsedNodesIdx;
int nUsedNodes;
int nMaxUsedNodes;
int bStopIntersection;
int bCurNodeUsed;
matrix3x3f R,R_rel;
vectorf offset,offset_rel;
float scale,rscale, scale_rel,rscale_rel;
int bTransformUpdated;
vectorf v;
vectorf w,centerOfMass;
vectorf centerOfRotation;
intersection_params *pParams;
vectorf axisContactNormal;
vectorf sweepdir,sweepdir_loc;
float sweepstep,sweepstep_loc;
vectorf ptOutsidePivot;
int typeprim;
primitive *primbuf; // used to get node contents
primitive *primbuf1;// used to get unprojection candidates
int szprimbuf,szprimbuf1;
int *iFeature_buf; // feature that led to this primitive
short *idbuf; // ids of unprojection candidates
int szprim;
surface_desc *surfaces; // the last potentially surfaces
edge_desc *edges; // the last potentially contacting edges
int nSurfaces,nEdges;
float minAreaEdge;
geom_contact *contacts;
int *pnContacts;
int nMaxContacts;
};
enum BVtreetypes { BVT_OBB=0, BVT_AABB=1, BVT_SINGLEBOX=2, BVT_RAY=3, BVT_HEIGHTFIELD=4 };
class CBVTree {
public:
virtual ~CBVTree() {}
virtual int GetType() = 0;
virtual void GetBBox(box *pbox) {}
virtual int MaxPrimsInNode() { return 1; }
virtual float Build(CGeometry *pGeom) = 0;
virtual void SetGeomConvex() {}
virtual int PrepareForIntersectionTest(geometry_under_test *pGTest) {
pGTest->pUsedNodesMap = 0;
pGTest->pUsedNodesIdx = 0;
pGTest->nMaxUsedNodes = 0;
pGTest->nUsedNodes = -1;
return 1;
}
virtual void CleanupAfterIntersectionTest(geometry_under_test *pGTest) {}
virtual void GetNodeBV(BV *&pBV, int iNode=0) = 0;
virtual void GetNodeBV(BV *&pBV, const vectorf &sweepdir,float sweepstep, int iNode=0) = 0;
virtual void GetNodeBV(const matrix3x3f &Rw,const vectorf &offsw,float scalew, BV *&pBV, int iNode=0) = 0;
virtual void GetNodeBV(const matrix3x3f &Rw,const vectorf &offsw,float scalew, BV *&pBV, const vectorf &sweepdir,float sweepstep, int iNode=0) = 0;
virtual float SplitPriority(const BV* pBV) { return 0.0f; }
virtual void GetNodeChildrenBVs(const matrix3x3f &Rw,const vectorf &offsw,float scalew, const BV *pBV_parent, BV *&pBV_child1,BV *&pBV_child2) {}
virtual void GetNodeChildrenBVs(const BV *pBV_parent, BV *&pBV_child1,BV *&pBV_child2) {}
virtual void GetNodeChildrenBVs(const BV *pBV_parent, const vectorf &sweepdir,float sweepstep, BV *&pBV_child1,BV *&pBV_child2) {}
virtual void ReleaseLastBVs() {}
virtual void ReleaseLastSweptBVs() {}
virtual void GetMemoryStatistics(ICrySizer *pSizer) {}
virtual void Save(CMemStream &stm) {}
virtual void Load(CMemStream &stm, CGeometry *pGeom) {}
virtual int GetNodeContents(int iNode, BV *pBVCollider,int bColliderUsed,int bColliderLocal,
geometry_under_test *pGTest,geometry_under_test *pGTestOp) = 0;
virtual int GetNodeContentsIdx(int iNode, int &iStartPrim) { iStartPrim=0; return 1; }
virtual void MarkUsedTriangle(int itri, geometry_under_test *pGTest) {}
};
#endif

617
CryPhysics/cylindergeom.cpp Normal file
View File

@@ -0,0 +1,617 @@
#include "stdafx.h"
#include "utils.h"
#include "primitives.h"
#include "unprojectionchecks.h"
#include "bvtree.h"
#include "singleboxtree.h"
#include "geometry.h"
#include "cylindergeom.h"
#include "trimesh.h"
#include "boxgeom.h"
vector2df g_CylCont[64];
int g_CylContId[64];
CCylinderGeom* CCylinderGeom::CreateCylinder(cylinder *pcyl)
{
m_cyl.center = pcyl->center;
m_cyl.axis = pcyl->axis;
m_cyl.hh = pcyl->hh;
m_cyl.r = pcyl->r;
box bbox;
bbox.Basis.SetRow(2,m_cyl.axis);
//bbox.Basis.SetRow(0,m_cyl.axis.orthogonal().normalized());
bbox.Basis.SetRow(0,GetOrthogonal(m_cyl.axis).normalized());
bbox.Basis.SetRow(1,m_cyl.axis ^ bbox.Basis.GetRow(0));
bbox.bOriented = 1;
bbox.center = m_cyl.center;
bbox.size.z = m_cyl.hh;
bbox.size.x = bbox.size.y = m_cyl.r;
m_Tree.SetBox(&bbox);
m_Tree.Build(this);
m_minVtxDist = (m_cyl.r+m_cyl.hh)*1E-4f;
return this;
}
int CCylinderGeom::CalcPhysicalProperties(phys_geometry *pgeom)
{
pgeom->pGeom = this;
pgeom->origin = m_cyl.center;
//pgeom->q = quaternionf(vectorf(0,0,1),m_cyl.axis);
pgeom->q.SetRotationV0V1(vectorf(0,0,1),m_cyl.axis);
pgeom->V = sqr(m_cyl.r)*m_cyl.hh*(pi*2);
float x2=pi*m_cyl.hh*sqr(sqr(m_cyl.r))*(1.0/2), z2=pi*sqr(m_cyl.r)*cube(m_cyl.hh)*(2.0/3);
pgeom->Ibody.Set(x2+z2,x2+z2,x2*2);
return 1;
}
int CCylinderGeom::PointInsideStatus(const vectorf &pt)
{
vectorf ptr; float h;
ptr = pt-m_cyl.center; h = m_cyl.axis*ptr; ptr -= m_cyl.axis*h;
return isneg(ptr.len2()-sqr(m_cyl.r)) & isneg(fabs_tpl(h)-m_cyl.hh);
}
int CCylinderGeom::PrepareForIntersectionTest(geometry_under_test *pGTest, CGeometry *pCollider,geometry_under_test *pGTestColl, bool bKeepPrevContacts)
{
static short g_CylIdBuf[1];
static surface_desc g_CylSurfaceBuf[1];
static edge_desc g_CylEdgeBuf[1];
pGTest->pGeometry = this;
pGTest->pBVtree = &m_Tree;
m_Tree.PrepareForIntersectionTest(pGTest);
pGTest->primbuf = pGTest->primbuf1 = g_CylBuf+g_CylBufPos++;
pGTest->szprimbuf = 1;
pGTest->typeprim = cylinder::type;
pGTest->szprim = sizeof(cylinder);
pGTest->idbuf = g_CylIdBuf;
pGTest->surfaces = g_CylSurfaceBuf;
pGTest->edges = g_CylEdgeBuf;
pGTest->minAreaEdge = pi*m_cyl.r*2.0f/m_nTesselation;
return 1;
}
void CCylinderGeom::PrepareCylinder(cylinder *pcyl, geometry_under_test *pGTest)
{
pcyl->center = pGTest->R*m_cyl.center*pGTest->scale + pGTest->offset;
pcyl->axis = pGTest->R*m_cyl.axis;
pcyl->hh = m_cyl.hh*pGTest->scale;
pcyl->r = m_cyl.r*pGTest->scale;
}
int CCylinderGeom::PreparePrimitive(geom_world_data *pgwd, primitive *&pprim)
{
cylinder *pcyl = g_CylBuf+g_CylBufPos;
g_CylBufPos = g_CylBufPos+1 & sizeof(g_CylBuf)/sizeof(g_CylBuf[0])-1;
pcyl->center = pgwd->R*m_cyl.center*pgwd->scale + pgwd->offset;
pcyl->axis = pgwd->R*m_cyl.axis;
pcyl->hh = m_cyl.hh*pgwd->scale;
pcyl->r = m_cyl.r*pgwd->scale;
pprim = pcyl;
return cylinder::type;
}
int CCylinderGeom::GetPrimitiveList(int iStart,int nPrims, int typeCollider,primitive *pCollider,int bColliderLocal,
geometry_under_test *pGTest,geometry_under_test *pGTestOp, primitive *pRes,short *pResId)
{
PrepareCylinder((cylinder*)pRes, pGTest);
pGTest->bTransformUpdated = 0; *pResId = -1;
return 1;
}
int CCylinderGeom::GetUnprojectionCandidates(int iop,const contact *pcontact, primitive *&pprim,int *&piFeature, geometry_under_test *pGTest)
{
if (pGTest->bTransformUpdated) {
pprim = pGTest->primbuf1;
PrepareCylinder((cylinder*)pprim, pGTest);
}
cylinder *pcyl = (cylinder*)pprim;
pGTest->idbuf[0] = -1;
int iFeature = pcontact->iFeature[iop],iCap;
float r2,hh;
r2 = (pcontact->pt-pcyl->center^pcyl->axis).len2();
hh = (pcontact->pt-pcyl->center)*pcyl->axis;
if ((iFeature&0xE0)!=0x20 && fabs_tpl(r2-sqr(pcyl->r))<sqr(m_minVtxDist) && fabs_tpl(fabs_tpl(hh)-pcyl->hh)<m_minVtxDist)
iFeature = 0x20 | isnonneg(hh);
if ((iFeature&0xE0)==0x20 || iFeature>0x40) {
iCap = (iFeature&3)-(iFeature>>6);
pGTest->surfaces[0].n = pcyl->axis*((iCap<<1)-1);
pGTest->surfaces[0].idx = 0;
pGTest->surfaces[0].iFeature = 0x40 | iCap+1;
pGTest->nSurfaces = 1;
} else
pGTest->nSurfaces = 0;
if ((iFeature&0xE0)==0x20 || iFeature==0x40) {
pGTest->edges[0].dir = pcyl->axis;
pGTest->edges[0].n[0] = pcyl->center-pcontact->pt^pcyl->axis;
pGTest->edges[0].n[1] = -pGTest->edges[0].n[0];
pGTest->edges[0].idx = 0;
pGTest->edges[0].iFeature = iFeature;
pGTest->nEdges = 1;
} else
pGTest->nEdges = 0;
return 1;
}
int CCylinderGeom::PreparePolygon(coord_plane *psurface, int iPrim,int iFeature, geometry_under_test *pGTest, vector2df *&ptbuf,
int *&pVtxIdBuf,int *&pEdgeIdBuf)
{
int i,icap;
float ang,step;
vectorf axes[3],pt,center;
axes[2] = pGTest->R*m_cyl.axis;
//axes[0] = axes[2].orthogonal().normalized();
axes[0] = GetOrthogonal(axes[2]).normalized();
axes[1] = axes[2]^axes[0];
icap = (((iFeature&3)-(iFeature>>6)<<1)-1);
center = pGTest->R*m_cyl.center*pGTest->scale + axes[2]*(m_cyl.hh*pGTest->scale*icap) + pGTest->offset;
if (psurface->n.len2()==0) {
psurface->n = axes[2]*icap;
psurface->axes[0] = axes[0]; psurface->axes[1] = axes[1]*icap;
psurface->origin = center;
}
center -= psurface->origin;
step = (pi*2/m_nTesselation)*sgnnz(axes[2]*psurface->n);
axes[0] *= (pGTest->scale*m_cyl.r);
axes[1] *= (pGTest->scale*m_cyl.r);
for(i=0,ang=0;i<m_nTesselation;i++,ang+=step) {
pt = center + axes[0]*cos_tpl(ang) + axes[1]*sin_tpl(ang);
g_CylCont[i].set(pt*psurface->axes[0],pt*psurface->axes[1]);
g_CylContId[i] = 0x20 | icap+1>>1;
}
g_CylCont[i] = g_CylCont[0]; g_CylContId[2] = g_CylContId[0];
ptbuf = g_CylCont;
pVtxIdBuf = pEdgeIdBuf = g_CylContId;
return i;
}
int CCylinderGeom::PreparePolyline(coord_plane *psurface, int iPrim,int iFeature, geometry_under_test *pGTest, vector2df *&ptbuf,
int *&pVtxIdBuf,int *&pEdgeIdBuf)
{
vectorf axis,center,pt;
axis = pGTest->R*m_cyl.axis;
center = pGTest->R*m_cyl.center*pGTest->scale + pGTest->offset;
pt = center + axis*(m_cyl.hh*pGTest->scale) - psurface->origin;
g_CylCont[0].set(pt*psurface->axes[0],pt*psurface->axes[1]);
pt = center - axis*(m_cyl.hh*pGTest->scale) - psurface->origin;
g_CylCont[1].set(pt*psurface->axes[0],pt*psurface->axes[1]);
g_CylCont[2] = g_CylCont[0];
g_CylContId[0] = g_CylContId[1] = g_CylContId[2] = 0x40;
ptbuf = g_CylCont;
pVtxIdBuf = pEdgeIdBuf = g_CylContId;
return 2;
}
int CCylinderGeom::FindClosestPoint(geom_world_data *pgwd, int &iPrim,int &iFeature, const vectorf &ptdst0,const vectorf &ptdst1,
vectorf *ptres, int nMaxIters)
{
vectorr axis,center,pt,l,ptdst[]={ptdst0,ptdst1},ptresi[2];
real r,hh,r2;
int i,icap,bLine;
axis = pgwd->R*m_cyl.axis;
center = pgwd->R*m_cyl.center*pgwd->scale + pgwd->offset;
r = m_cyl.r*pgwd->scale; r2 = r*r; hh = m_cyl.hh*pgwd->scale;
pt = ptdst0-center; ptres[1] = ptdst0;
if (bLine = isneg(r2*1E-6f-(l=ptdst1-ptdst0).len2())) {
vectorr n,la,pa;
real n2,l2,t0,t1,kt,pl,pal,roots[4];
polynomial_tpl<real,4> pn;
n = l^axis; n2 = n.len2();
if (isneg(n2*r2-sqr(pt*n)) & inrange(t0=(-pt^axis)*n, (real)0,n2) & inrange(t1=(-pt^l)*n, (real)0,n2*hh)) {
ptres[1] = ptdst0+l*(t0/n2); // line-cylinder side distance
ptres[0] = center+axis*(axis*(ptres[1]-center));
ptres[0] = center+(ptres[1]-ptres[0]).normalized()*r;
return 1;
}
icap = sgnnz(t1);
la = l-axis*(l*axis); l2 = l.len2(); kt = l2-sqr(axis*l);
pt = ptdst0-(center+axis*(hh*icap));
pa = pt-axis*(pt*axis); pl = pt*l; pal = pa*l;
pn = psqr(P1(l2)+pt*l)*(P2(la.len2())+P1((pa*la)*2)+pa.len2()) - psqr(P1(kt*r)+(pa*l)*r);
if (pn.nroots(0,1)) for(i=pn.findroots(0,1,roots)-1;i>=0;i--)
if ((pl+l2*roots[i])*(pal+kt*roots[i])>0) { // skips phantom roots
pa = pt+l*roots[i];
if (isneg(r2-(pa^axis).len2()) & isneg((pa*axis)*-icap)) { // check if this is the global minimum
center += axis*(hh*icap);
ptres[1] = center + pa;
ptres[0] = center + (pa-axis*(axis*pa)).normalized()*r;
return 1;
}
}
}
ptresi[1].zero();
for(i=0;i<=bLine;i++) {
pt = ptdst[i]-center;
if (fabsf(pt*axis)<hh) { // the closest point lies on cylinder side
pt -= axis*(axis*pt);
ptresi[i] = ptdst[i]-pt+pt.normalized()*r;
continue;
}
if ((pt^axis).len2()<r*r) { // .. cylinder cap
ptresi[i] = ptdst[i]+axis*(sgn(pt*axis)*hh-pt*axis);
continue;
}
// cylinder cap edge
ptresi[i] = center+axis*(sgn(axis*pt)*hh) + (pt-axis*(axis*pt)).normalized()*r;
}
i = bLine & isneg((ptresi[1]-ptdst[1]).len2()-(ptresi[0]-ptdst[0]).len2());
ptres[0] = ptresi[i];
ptres[1] = ptdst[i];
return 1;
}
int CCylinderGeom::UnprojectSphere(vectorf center,float r,float rsep, contact *pcontact)
{
vectorf dc = center-m_cyl.center;
float axdist2,capdist,r2=sqr(m_cyl.r);
axdist2 = max((dc^m_cyl.axis).len2(),r2);
capdist = max(0.0f,fabsf(dc*m_cyl.axis)-m_cyl.hh);
if (sqr_signed(axdist2+r2+sqr(capdist)-sqr(rsep)) > axdist2*r2*4)
return 0;
unprojection_mode umode;
sphere sph;
sph.center = center;
sph.r = r;
umode.dir.Set(0,0,0);
cylinder_sphere_lin_unprojection(&umode,&m_cyl,-1,&sph,-1,pcontact,0);
pcontact->pt -= umode.dir*pcontact->t;
return 1;
}
void CCylinderGeom::CalcVolumetricPressure(geom_world_data *gwd, const vectorf &epicenter,float k,float rmin,
const vectorf &centerOfMass, vectorf &P,vectorf &L)
{
vectorf c,dc;
float blendf,area,r;
c = gwd->R*m_cyl.center*gwd->scale + gwd->offset;
dc = c-epicenter; r = dc.len();
if (r>m_cyl.r*0.01f)
dc/=r;
else dc.Set(0,0,1);
blendf = (gwd->R*m_cyl.axis^dc).len();
area = (pi*sqr(m_cyl.r)*(1.0f-blendf) + m_cyl.hh*m_cyl.r*4*blendf)*sqr(gwd->scale);
P += dc*(area*k/sqr(max(r,rmin)));
}
// debug testing code
/*float x,x0,dx=r*0.001f,Stest,Stesta,CxStest,CxStesta,Vtest,CxVtest,CzVtest,CxVtesta,CzVtesta;
for(x0=a,Vtest=CxVtest=CzVtest=0; x0<b; x0+=dx) {
for(x=x0,Stest=CxStest=0; x<b; x+=dx) {
Stest += sqrt_tpl(r2-x*x)*2*dx;
CxStest += x*sqrt_tpl(r2-x*x)*2*dx;
}
Stesta = b*sqrt_tpl(r2-b*b)+r2*asin_tpl(b*rinv)-x0*sqrt_tpl(r2-x0*x0)-r2*asin_tpl(x0*rinv);
CxStesta = (-2.0f/3)*(cube(sqrt_tpl(r2-b*b))-cube(sqrt_tpl(r2-x0*x0)));
Vtest += Stest*dx*k;
CxVtest += CxStest*dx*k;
CzVtest += ((x0-a)*k+z0)*Stest*dx*k;
}*/
/*CTriMesh mesh;
vectorf pt3d[48],normals[92];
int idx[92*3];float x,y;
axes.x=m_cyl.axis.orthogonal().normalized(); axes.y=m_cyl.axis^axes.x;
for(i=0,x=r,y=0; i<24; i++) {
pt3d[i] = m_cyl.center+axes.x*x+axes.y*y-m_cyl.axis*m_cyl.hh;
pt3d[i+24] = pt3d[i]+m_cyl.axis*(2*m_cyl.hh);
k=x; x=x*cos_tpl(pi/12)-y*sin_tpl(pi/12); y=y*cos_tpl(pi/12)+k*sin_tpl(pi/12);
}
for(i=0;i<22;i++) { idx[i*3]=0; idx[i*3+1]=i+2; idx[i*3+2]=i+1; normals[i]=-m_cyl.axis; }
for(;i<44;i++) { idx[i*3]=24; idx[i*3+1]=i+3; idx[i*3+2]=i+4; normals[i]=m_cyl.axis; }
for(;i<92;i++) {
idx[i*3]=i-44>>1; idx[i*3+1]=idx[i*3]+1; idx[i*3+2]=idx[i*3]+24; normals[i]=(pt3d[idx[i*3+1]]-pt3d[idx[i*3]]^pt3d[idx[i*3+2]]-pt3d[idx[i*3]]).normalized(); i++;
idx[i*3]=(i-44>>1)+1; idx[i*3+1]=idx[i*3]+24; idx[i*3+2]=idx[i*3]+23; normals[i]=(pt3d[idx[i*3+1]]-pt3d[idx[i*3]]^pt3d[idx[i*3+2]]-pt3d[idx[i*3]]).normalized();
}
float V1; vectorf c1;
mesh.m_pVertices.data = pt3d;
mesh.m_pIndices = idx;
mesh.m_pNormals = normals;
mesh.m_nVertices=48; mesh.m_nTris=92;
V1 = mesh.CalculateBuoyancy(pplane,pgwd,c1);
if (fabs_tpl(V1-Vaccum)>V1*0.05f || (c1-massCenter).len2()>r2*sqr(0.05f))
i=0;
mesh.m_pNormals=0; mesh.m_pIndices=0; mesh.m_pVertices.data=0;*/
/*vectorf axisx,axisy,pt3d[16];
axisx = vectorf(1,0,0).rotated(rotax,n.z,-sina);
axisy = vectorf(0,1,0).rotated(rotax,n.z,-sina);
pt[0].set(r,0); itype[0]=1; pt3d[0] = center+axisx*pt[0].x+axisy*pt[0].y;
for(i=1;i<8;i++) {
itype[i]=1; pt[i].x=(pt[i-1].x-pt[i-1].y)*(sqrt2/2); pt[i].y=(pt[i-1].x+pt[i-1].y)*(sqrt2/2);
pt3d[i] = center+axisx*pt[i].x+axisy*pt[i].y;
} npt=8; pt[8]=pt[0];
vectorf Ptest(zero),Ltest(zero);
CalcMediumResistance(pt3d,8,n,*pplane,pgwd->v,pgwd->w,pgwd->centerOfMass,Ptest,Ltest);*/
/*Ptest += dP.rotated(rotax,n.z,-sina);
Ltest += dL.rotated(rotax,n.z,-sina);
if (Ptest.len()+Ltest.len()>0.001)
i=0;*/
float CCylinderGeom::CalculateBuoyancy(const plane *pplane, const geom_world_data *pgwd, vectorf &massCenter)
{
Vec3_tpl<vectorf> axes;
float r=m_cyl.r*pgwd->scale, h=m_cyl.hh*pgwd->scale*2, r2=r*r, rinv=1.0f/r,
denom,k,a,b,z0,z1,ya,yb,anglea,angleb,V[4],Vaccum;
vectorf n = pplane->n, center = pgwd->R*m_cyl.center+pgwd->offset, com[3],com_accum;
int i,nPieces=0;
axes.z = pgwd->R*m_cyl.axis; axes.z *= sgnnz(axes.z*n);
center -= axes.z*(h*0.5f); axes.y = n^axes.z;
massCenter = center+axes.z*(h*0.5f);
if (axes.y.len2()<0.0001f) {
// water plane is perpendicular to cylinder axis
z0 = max(0.0f,min(h,(pplane->origin-center)*pplane->n));
massCenter = center+axes.z*(z0*0.5f);
return pi*r2*z0;
}
axes.y.normalize(); axes.x = axes.y^axes.z;
denom = 1.0f/(axes.x*n);
a = ((pplane->origin-center)*n)*denom;
if (a>=r)
return 0;
else if (a<-r) {
if (sqr(axes.z*n)<0.0001f)
return pi*r2*h;
a = -r; z0 = ((pplane->origin-(center-axes.x*r))*n)/ (axes.z*n);
V[nPieces] = pi*r2*z0; com[nPieces++] = axes.z*(z0*0.5f*V[nPieces]);
} else z0 = 0;
b = ((pplane->origin-(center+axes.z*h))*n)*denom;
if (b<-r)
return pi*r2*h;
else if (b>r) {
b = r; z1 = ((pplane->origin-(center+axes.x*r))*n)/ (axes.z*n);
} else {
z1 = h; yb = sqrt_tpl(r2-b*b);
V[nPieces] = (r2*(pi*0.5f-asin_tpl(b*rinv))-b*yb)*(h-z0);
com[nPieces++] = axes.x*((2.0f/3)*cube(yb)*(h-z0)) + axes.z*((h+z0)*0.5f*V[nPieces]);
}
if (b>a+r*0.01f) {
denom = 1.0f/(b-a); k = (z1-z0)*denom;
ya = sqrt_tpl(r2-a*a); anglea = asin_tpl(a*rinv);
yb = sqrt_tpl(r2-b*b); angleb = asin_tpl(b*rinv);
V[nPieces] = k*((b*yb+r2*angleb)*(b-a)+(1.0f/3)*(cube(yb)-cube(ya))-r2*(b*angleb-a*anglea+yb-ya));
com[nPieces] = axes.z*(k*k*0.5f*((b*yb+r2*angleb)*(b*b-a*a)+0.5f*(b*cube(yb)-a*cube(ya))-r2*(0.75f*(b*yb-a*ya)-
0.25f*r2*(angleb-anglea)+b*b*angleb-a*a*anglea)) + V[nPieces]*(z0-a*k));
com[nPieces++] += axes.x*((2.0f/3)*k*(0.25f*(b*cube(yb)-a*cube(ya))+(3.0f/8)*r2*(b*yb-a*ya+r2*(angleb-anglea))-
cube(yb)*(b-a)));
}
for(i=0,Vaccum=0,com_accum.Set(0,0,0);i<nPieces;i++) {
Vaccum += V[i]; com_accum += com[i];//*V[i];
}
if (Vaccum>0)
massCenter = center+com_accum/Vaccum;
else Vaccum=0;
return Vaccum;
}
int crop_polyarc2d_with_line(const vector2df *pt,const int *itype,int npt, float r, vector2df *ptout,int *itypeout,
const vector2df &p0, const vector2df &l)
{
if (npt==0) return 0;
vector2df d0,c,ptt;
quotientf at[2],a[2],t[3];
float ka,kb,kc,kd;
int state,i,nout=0,i0,i1,j;
ka=l.len2(); kb=p0*l; kc=p0.len2()-r*r;
if ((kd=kb*kb-ka*kc)>=0) {
t[0].y=t[1].y=ka; kd=sqrt_tpl(kd);
t[0].x=-kb-kd; ptt = p0*t[0].y+l*t[0].x; at[0] = fake_atan2(ptt.y,ptt.x);
t[1].x=-kb+kd; ptt = p0*t[1].y+l*t[1].x; at[1] = fake_atan2(ptt.y,ptt.x);
}
state = isnonneg(l ^ pt[0]-p0);
for(i=0; i<npt; i++) {
i0=i1 = 0;
if (itype[i]) {
d0=pt[i+1]-pt[i]; c=pt[i]-p0;
t[2].y=d0^l; t[2].x=l^c;
if (inrange(t[2].x, 0.0f,t[2].y)) {
i0=2;i1=3; t[2].x=d0^c;
}
} else if (kd>=0) {
a[0] = fake_atan2(pt[i].y,pt[i].x);
a[1] = fake_atan2(pt[i+1].y,pt[i+1].x);
i0 = isneg(isneg(a[0]-at[0])+isneg(at[0]-a[1])+isneg(a[1]-a[0])-2);
i1 = isneg(1-isneg(a[0]-at[1])-isneg(at[1]-a[1])-isneg(a[1]-a[0]))+1;
}
if (state) {
ptout[nout]=pt[i]; itypeout[nout++]=itype[i];
}
for(j=i0; j<i1; j++,state^=1) {
ptout[nout]=p0+l*t[j].x/t[j].y;
itypeout[nout++] = itype[i]|state;
}
}
return nout;
}
void CCylinderGeom::CalculateMediumResistance(const plane *pplane, const geom_world_data *pgwd, vectorf &dPres,vectorf &dLres)
{
vectorf n,rotax,v,w,center,dir,org,pt0,dP(zero),dL(zero),ptside[4];
vector2df ptbuf0[16],ptbuf1[16],*pt=ptbuf0,*pt1=ptbuf1,*ptt;
float sina,r,rr,r2,hh,x0,y0,x1,y1,dx,dy,Fx,Fxy,Fxx,Fxxy,Fxyy,Fxxx,alpha,square;
int i,icap,npt,sgx,itypebuf0[16],itypebuf1[16],*itype=itypebuf0,*itype1=itypebuf1,*itypet;
dPres.zero(); dLres.zero();
r2 = sqr(r=m_cyl.r*pgwd->scale);
hh = m_cyl.hh*pgwd->scale;
n = pgwd->R*-m_cyl.axis;
rotax = n^vectorf(0,0,1);
sina = rotax.len();
if (sina>0.001f)
rotax/=sina;
else
rotax.Set(1,0,0);
center = pgwd->R*m_cyl.center*pgwd->scale+pgwd->offset+n*hh;
org = center + pplane->n*(pplane->n*(pplane->origin-center));
rr = 1/r;
x1 = 0.965925826f; y1 = 0.258819045f; // 15 degrees sin/cos
ptside[0] = vectorf(x0=r,y0=0,0).rotated(rotax,n.z,-sina)+center;
for(i=0; i<12; i++) {
ptside[1] = ptside[0];
dx = x0; x0 = (x0*sqrt3-y0)*0.5f; y0 = (y0*sqrt3+dx)*0.5f;
ptside[0] = vectorf(x0,y0,0).rotated(rotax,n.z,-sina)+center;
ptside[2] = ptside[1]-n*(hh*2); ptside[3] = ptside[0]-n*(hh*2);
CalcMediumResistance(ptside,4, vectorf(x1,y1,0).rotated(rotax,n.z,-sina),
*pplane,pgwd->v,pgwd->w,pgwd->centerOfMass,dPres,dLres);
dx = x1; x1 = (x1*sqrt3-y1)*0.5f; y1 = (y1*sqrt3+dx)*0.5f;
}
for(icap=-1; icap<=1; icap+=2,n.flip(),center+=n*(hh*2),rotax.flip()) {
v = (pgwd->v+(pgwd->w^center-pgwd->centerOfMass)).rotated(rotax,n.z,sina);
w = pgwd->w.rotated(rotax,n.z,sina);
pt[0].set(0,r); pt[1].set(0,-r); pt[2]=pt[0];
itype[0]=itype[1] = 0; npt = 2;
dir = pplane->n*(pplane->n*n)-n;
if (dir.len2() > 0.001f)
npt = crop_polyarc2d_with_line(pt,itype,npt, r, pt1,itype1,
vector2df((org+dir*(((center-org)*n)/(dir*n))-center).rotated(rotax,n.z,sina)),
-vector2df(cross_with_ort(pplane->n.rotated(rotax,n.z,sina),2)));
else {
ptt=pt;pt=pt1;pt1=ptt; itypet=itype;itype=itype1;itype1=itypet;
if (center*pplane->n > org*pplane->n)
npt = 0;
} pt1[npt] = pt1[0];
dir = pgwd->w^n;
if (dir.len2() > w.len2()*0.001f)
npt = crop_polyarc2d_with_line(pt1,itype1,npt, r, pt,itype,
vector2df((dir*((pgwd->v*n-center*dir)/dir.len2())).rotated(rotax,n.z,sina)), vector2df(w));
else {
ptt=pt;pt=pt1;pt1=ptt; itypet=itype;itype=itype1;itype1=itypet;
if (center*(pgwd->w^n) > pgwd->v*n)
npt = 0;
} pt[npt] = pt[0];
for(i=0,square=0,dP.zero(),dL.zero(); i<npt; i++) {
x0=pt[i].x; y0=pt[i].y; x1=pt[i+1].x; y1=pt[i+1].y;
if (itype[i]) {
dx = x1-x0; dy = y1-y0;
Fx = (x0*y1-x1*y0)*0.5f;
Fxy = dy*(x0*y0 + (dx*y0+dy*x0)*0.5f + dx*dy*(1.0f/3));
Fxx = dy*(x0*x0 + dx*x0 + dx*dx*(1.0f/3));
Fxxy = dy*(dx*dx*dy*0.25f + (dx*dx*y0+dx*dy*x0*2)*(1.0f/3) + (x0*y0*dx*2+x0*x0*dy)*0.5f + x0*x0*y0);
Fxyy = dy*(dy*dy*dx*0.25f + (dy*dy*x0+dy*dx*y0*2)*(1.0f/3) + (y0*x0*dy*2+y0*y0*dx)*0.5f + y0*y0*x0);
Fxxx = dy*(dx*dx*dx*0.25f + dx*dx*x0 + dx*x0*x0*1.5f + x0*x0*x0);
} else {
alpha = asin_tpl(max(-0.9999f,min(0.9999f,y1*rr)))-asin_tpl(max(-0.9999f,min(0.9999f,y0*rr)));
sgx = sgnnz(y1-y0);
Fx = r2*alpha*0.5f*sgx;
Fxy = (cube(x1)-cube(x0))*(-1.0f/3);
Fxx = r2*(y1-y0)-(cube(y1)-cube(y0))*(1.0f/3);
Fxxy = r2*(sqr(y1)-sqr(y0))*0.5f-(cube(y1)-cube(y0))*(1.0f/3);
Fxyy = (y1*cube(x1)-y0*cube(x0))*(-1.0f/4) + r2*(1.0f/8)*(x1*y1-x0*y0+r2*alpha*sgx);
Fxxx = 0.25f*(y1*cube(x1)-y0*cube(x0)+1.5f*r2*(y1*x1-y0*x0+r2*alpha*sgx));
}
square += Fx;
dP.z += w.x*Fxy-w.y*0.5f*Fxx;
dL.x += v.z*Fxy;
dL.y -= v.z*0.5f*Fxx;
dL.x += w.x*Fxyy-w.y*0.5f*Fxxy;
dL.y -= w.x*0.5*Fxxy-w.y*(1.0f/3)*Fxxx;
}
dP.z += v.z*square;
dPres -= dP.rotated(rotax,n.z,-sina);
dLres -= dL.rotated(rotax,n.z,-sina);
}
}
int CCylinderGeom::DrawToOcclusionCubemap(const geom_world_data *pgwd, int iStartPrim,int nPrims, int iPass, int *pGrid[6],int nRes,
float rmin,float rmax,float zscale)
{
CBoxGeom geombox;
geombox.m_box = m_Tree.m_Box;
return geombox.DrawToOcclusionCubemap(pgwd,iStartPrim,nPrims,iPass,pGrid,nRes,rmin,rmax,zscale);
}
void CCylinderGeom::DrawWireframe(void (*DrawLineFunc)(float*,float*), geom_world_data *gwd, int iLevel)
{
if (iLevel==0) {
int i; float step,ang;
vectorf axes[3],center,pt0,pt1;
step = (pi*2/m_nTesselation);
axes[2] = gwd->R*m_cyl.axis;
// axes[0] = axes[2].orthogonal().normalized();
axes[0] = GetOrthogonal(axes[2]).normalized();
axes[1] = axes[2]^axes[0];
axes[0] *= m_cyl.r*gwd->scale; axes[1] *= m_cyl.r*gwd->scale;
axes[2] *= m_cyl.hh*gwd->scale;
center = gwd->R*m_cyl.center*gwd->scale + gwd->offset;
pt0 = center+axes[0];
for(i=0,ang=step;i<m_nTesselation;i++,ang+=step,pt0=pt1) {
pt1 = center + axes[0]*cos_tpl(ang) + axes[1]*sin_tpl(ang);
DrawLineFunc(pt0-axes[2], pt1-axes[2]);
DrawLineFunc(pt0+axes[2], pt1+axes[2]);
DrawLineFunc(pt1-axes[2], pt1+axes[2]);
}
} else {
BV *pbbox;
ResetGlobalPrimsBuffers();
m_Tree.GetNodeBV(gwd->R,gwd->offset,gwd->scale, pbbox);
DrawBBox(DrawLineFunc,gwd, &m_Tree,(BBox*)pbbox,iLevel-1);
}
}
void CCylinderGeom::GetMemoryStatistics(ICrySizer *pSizer)
{
pSizer->AddObject(this, sizeof(CCylinderGeom));
}
void CCylinderGeom::Save(CMemStream &stm)
{
stm.Write(m_cyl);
stm.Write(m_nTesselation);
m_Tree.Save(stm);
}
void CCylinderGeom::Load(CMemStream &stm)
{
stm.Read(m_cyl);
stm.Read(m_nTesselation);
m_Tree.Load(stm,this);
}

50
CryPhysics/cylindergeom.h Normal file
View File

@@ -0,0 +1,50 @@
#ifndef cylindergeom_h
#define cylindergeom_h
#pragma once
class CCylinderGeom : public CPrimitive {
public:
CCylinderGeom() { m_iCollPriority = 3; m_nTesselation = 18; m_minVtxDist = 0; }
CCylinderGeom* CreateCylinder(cylinder *pcyl);
void PrepareCylinder(cylinder *pcyl, geometry_under_test *pGTest);
virtual int PreparePrimitive(geom_world_data *pgwd,primitive *&pprim);
virtual int GetType() { return GEOM_CYLINDER; }
virtual void GetBBox(box *pbox) { m_Tree.GetBBox(pbox); }
virtual int CalcPhysicalProperties(phys_geometry *pgeom);
virtual int FindClosestPoint(geom_world_data *pgwd, int &iPrim,int &iFeature, const vectorf &ptdst0,const vectorf &ptdst1,
vectorf *ptres, int nMaxIters);
virtual int PointInsideStatus(const vectorf &pt);
virtual void CalcVolumetricPressure(geom_world_data *gwd, const vectorf &epicenter,float k,float rmin,
const vectorf &centerOfMass, vectorf &P,vectorf &L);
virtual float CalculateBuoyancy(const plane *pplane, const geom_world_data *pgwd, vectorf &massCenter);
virtual void CalculateMediumResistance(const plane *pplane, const geom_world_data *pgwd, vectorf &dPres,vectorf &dLres);
virtual int DrawToOcclusionCubemap(const geom_world_data *pgwd, int iStartPrim,int nPrims, int iPass, int *pGrid[6],int nRes,
float rmin,float rmax,float zscale);
virtual CBVTree *GetBVTree() { return &m_Tree; }
virtual int UnprojectSphere(vectorf center,float r,float rsep, contact *pcontact);
virtual int GetPrimitive(int iPrim, primitive *pprim) { *(cylinder*)pprim = m_cyl; return sizeof(cylinder); }
virtual void DrawWireframe(void (*DrawLineFunc)(float*,float*), geom_world_data *gwd, int iLevel);
virtual int PrepareForIntersectionTest(geometry_under_test *pGTest, CGeometry *pCollider,geometry_under_test *pGTestColl, bool bKeepPrevContacts=false);
virtual int GetPrimitiveList(int iStart,int nPrims, int typeCollider,primitive *pCollider,int bColliderLocal,
geometry_under_test *pGTest,geometry_under_test *pGTestOp, primitive *pRes,short *pResId);
virtual int GetUnprojectionCandidates(int iop,const contact *pcontact, primitive *&pprim,int *&piFeature, geometry_under_test *pGTest);
virtual int PreparePolygon(coord_plane *psurface, int iPrim,int iFeature, geometry_under_test *pGTest, vector2df *&ptbuf,
int *&pVtxIdBuf,int *&pEdgeIdBuf);
virtual int PreparePolyline(coord_plane *psurface, int iPrim,int iFeature, geometry_under_test *pGTest, vector2df *&ptbuf,
int *&pVtxIdBuf,int *&pEdgeIdBuf);
virtual void GetMemoryStatistics(ICrySizer *pSizer);
virtual void Save(CMemStream &stm);
virtual void Load(CMemStream &stm);
cylinder m_cyl;
int m_nTesselation;
CSingleBoxTree m_Tree;
};
#endif

158
CryPhysics/geoman.cpp Normal file
View File

@@ -0,0 +1,158 @@
#include "stdafx.h"
#include "utils.h"
#include "primitives.h"
#include "geometries.h"
#include "geoman.h"
void CGeomManager::InitGeoman()
{
m_nGeomChunks=0; m_nGeomsInLastChunk=0;
}
void CGeomManager::ShutDownGeoman()
{
int i,j;
for(i=0;i<m_nGeomChunks;i++) {
for(j=0;j<GEOM_CHUNK_SZ;j++) if (m_pGeoms[i][j].pGeom)
delete m_pGeoms[i][j].pGeom;
delete[] m_pGeoms[i];
}
if (m_nGeomChunks)
delete[] m_pGeoms;
m_nGeomChunks=0; m_nGeomsInLastChunk=0;
}
IGeometry *CGeomManager::CreateMesh(strided_pointer<const vectorf> pVertices,index_t *pIndices,const short *pIds,int nTris, int flags,bool bCopyTriangles,
bool bCopyVertices, float approx_tolerance, int nMinTrisPerNode,int nMaxTrisPerNode, float favorAABB)
{
vectorr axes[3],center;
primitive *pprim;
int i,itype = triangle::type;
if (nTris<=0)
return 0;
if (pIds) {
if (flags & mesh_uchar_ids)
for(i=1;i<nTris && ((char*)pIds)[i]==*(char*)pIds;i++);
else
for(i=1;i<nTris && pIds[i]==*pIds;i++);
} else i = nTris;
if (i==nTris) { // only try approximation if the mesh has one material
ComputeMeshEigenBasis(pVertices,pIndices,nTris, axes,center);
itype = ChoosePrimitiveForMesh(pVertices,pIndices,nTris, axes,center, flags,approx_tolerance, pprim);
}
if (itype==triangle::type)
return (new CTriMesh)->CreateTriMesh(pVertices,pIndices,pIds,nTris, flags,bCopyTriangles,bCopyVertices, nMinTrisPerNode,nMaxTrisPerNode, favorAABB);
else
return CreatePrimitive(itype,pprim);
}
IGeometry *CGeomManager::CreatePrimitive(int type, const primitive *pprim)
{
switch (type) {
case cylinder::type: return (new CCylinderGeom)->CreateCylinder((cylinder*)pprim);
case sphere::type: return (new CSphereGeom)->CreateSphere((sphere*)pprim);
case box::type: return (new CBoxGeom)->CreateBox((box*)pprim);
case heightfield::type: return (new CHeightfield)->CreateHeightfield((heightfield*)pprim);
case ray::type: return new CRayGeom((ray*)pprim);
}
return 0;
}
void CGeomManager::DestroyGeometry(IGeometry *pGeom)
{
pGeom->Release();
}
int CGeomManager::AddRefGeometry(phys_geometry *pgeom)
{
return ++pgeom->nRefCount;
}
int CGeomManager::UnregisterGeometry(phys_geometry *pgeom)
{
if (--pgeom->nRefCount!=0)
return pgeom->nRefCount;
pgeom->pGeom->Release();
pgeom->pGeom = 0;
if (pgeom-m_pGeoms[m_nGeomChunks-1]==m_nGeomsInLastChunk-1)
m_nGeomsInLastChunk--;
return 0;
}
phys_geometry *CGeomManager::GetFreeGeomSlot()
{
int i,j;
for(i=0;i<m_nGeomChunks-1;i++) {
for(j=0;j<GEOM_CHUNK_SZ && m_pGeoms[i][j].pGeom;j++);
if (j<GEOM_CHUNK_SZ) break;
}
if (i>=m_nGeomChunks-1)
for(j=0;j<m_nGeomsInLastChunk && m_pGeoms[i][j].pGeom;j++);
if (m_nGeomChunks==0 || j==GEOM_CHUNK_SZ) {
phys_geometry **t = m_pGeoms;
m_pGeoms = new phys_geometry*[m_nGeomChunks+1];
if (m_nGeomChunks) {
memcpy(m_pGeoms, t, sizeof(phys_geometry*)*m_nGeomChunks);
delete[] t;
}
i=m_nGeomChunks++; j=0;
memset(m_pGeoms[i] = new phys_geometry[GEOM_CHUNK_SZ], 0, sizeof(phys_geometry)*GEOM_CHUNK_SZ);
}
if (i==m_nGeomChunks-1 && j==m_nGeomsInLastChunk)
m_nGeomsInLastChunk++;
return m_pGeoms[i]+j;
}
phys_geometry *CGeomManager::RegisterGeometry(IGeometry *pGeom,int defSurfaceIdx)
{
phys_geometry *pgeom = GetFreeGeomSlot();
pGeom->CalcPhysicalProperties(pgeom);
pgeom->nRefCount = 1;
pgeom->surface_idx = defSurfaceIdx;
return pgeom;
}
void CGeomManager::SaveGeometry(CMemStream &stm, IGeometry *pGeom)
{
stm.Write(pGeom->GetType());
pGeom->Save(stm);
}
IGeometry *CGeomManager::LoadGeometry(CMemStream &stm)
{
int itype; stm.Read(itype);
IGeometry *pGeom;
switch (itype) {
case GEOM_TRIMESH: pGeom = new CTriMesh; break;
case GEOM_CYLINDER: pGeom = new CCylinderGeom; break;
case GEOM_SPHERE: pGeom = new CSphereGeom; break;
case GEOM_BOX: pGeom = new CBoxGeom; break;
}
pGeom->Load(stm);
return pGeom;
}
void CGeomManager::SavePhysGeometry(CMemStream &stm, phys_geometry *pgeom)
{
stm.Write(*pgeom);
SaveGeometry(stm,pgeom->pGeom);
}
phys_geometry *CGeomManager::LoadPhysGeometry(CMemStream &stm)
{
phys_geometry *pgeom = GetFreeGeomSlot();
stm.Read(*pgeom);
pgeom->pGeom = LoadGeometry(stm);
return pgeom;
}

36
CryPhysics/geoman.h Normal file
View File

@@ -0,0 +1,36 @@
#ifndef geoman_h
#define geoman_h
#pragma once
const int GEOM_CHUNK_SZ = 64;
class CGeomManager : public IGeomManager {
public:
CGeomManager() { InitGeoman(); }
~CGeomManager() { ShutDownGeoman(); }
void InitGeoman();
void ShutDownGeoman();
virtual IGeometry *CreateMesh(strided_pointer<const vectorf> pVertices,index_t *pIndices,const short *pIds,int nTris, int flags,bool bCopyTriangles=true,
bool bCopyVertices=true, float approx_tolerance=0.05f, int nMinTrisPerNode=2,int nMaxTrisPerNode=4, float favorAABB=1.0f);
virtual IGeometry *CreatePrimitive(int type, const primitive *pprim);
virtual void DestroyGeometry(IGeometry *pGeom);
virtual phys_geometry *RegisterGeometry(IGeometry *pGeom,int defSurfaceIdx=0);
virtual int AddRefGeometry(phys_geometry *pgeom);
virtual int UnregisterGeometry(phys_geometry *pgeom);
virtual void SaveGeometry(CMemStream &stm, IGeometry *pGeom);
virtual IGeometry *LoadGeometry(CMemStream &stm);
virtual void SavePhysGeometry(CMemStream &stm, phys_geometry *pgeom);
virtual phys_geometry *LoadPhysGeometry(CMemStream &stm);
virtual void RemapPhysGeometryFaceIds(phys_geometry *pgeom,short *pMap,int sz) { pgeom->pGeom->RemapFaceIds(pMap,sz); }
phys_geometry *GetFreeGeomSlot();
phys_geometry **m_pGeoms;
int m_nGeomChunks,m_nGeomsInLastChunk;
};
#endif

19
CryPhysics/geometries.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef geometries_h
#define geometries_h
#pragma once
#include "primitives.h"
#include "bvtree.h"
#include "geometry.h"
#include "trimesh.h"
#include "heightfieldbv.h"
#include "heightfieldgeom.h"
#include "singleboxtree.h"
#include "cylindergeom.h"
#include "spheregeom.h"
#include "raybv.h"
#include "raygeom.h"
#include "boxgeom.h"
#include "geoman.h"
#endif

788
CryPhysics/geometry.cpp Normal file
View File

@@ -0,0 +1,788 @@
#include "stdafx.h"
#include "utils.h"
#include "primitives.h"
#include "overlapchecks.h"
#include "intersectionchecks.h"
#include "unprojectionchecks.h"
#include "bvtree.h"
#include "geometry.h"
#include "singleboxtree.h"
#include "spheregeom.h"
indexed_triangle g_IdxTriBuf[256];
int g_IdxTriBufPos;
cylinder g_CylBuf[2];
int g_CylBufPos;
sphere g_SphBuf[2];
int g_SphBufPos;
box g_BoxBuf[2];
int g_BoxBufPos;
BBox g_BBoxBuf[128];
int g_BBoxBufPos;
surface_desc g_SurfaceDescBuf[64];
int g_SurfaceDescBufPos;
edge_desc g_EdgeDescBuf[64];
int g_EdgeDescBufPos;
int g_iFeatureBuf[64];
int g_iFeatureBufPos;
short g_IdBuf[256];
int g_IdBufPos;
int g_UsedNodesMap[8192];
int g_UsedNodesMapPos;
int g_UsedNodesIdx[64];
int g_UsedNodesIdxPos;
geom_contact g_Contacts[64];
int g_nTotContacts;
geom_contact_area g_AreaBuf[32];
int g_nAreas;
vectorf g_AreaPtBuf[256];
int g_AreaPrimBuf0[256],g_AreaFeatureBuf0[256],g_AreaPrimBuf1[256],g_AreaFeatureBuf1[256];
int g_nAreaPt;
extern vectorf g_BrdPtBuf[2048]; // from trimesh.cpp
extern int g_BrdPtBufPos; //
struct InitGeometryGlobals {
InitGeometryGlobals() {
memset(g_UsedNodesMap, 0, sizeof(g_UsedNodesMap));
g_EdgeDescBufPos = 0; g_IdBufPos = 0; g_IdxTriBufPos = 0;
g_SurfaceDescBufPos = 0; g_UsedNodesMapPos = 0; g_UsedNodesIdxPos = 0;
g_iFeatureBufPos = 0;
g_nAreas = 0; g_nAreaPt = 0; g_nTotContacts = 0;
}
};
static InitGeometryGlobals now;
#include "raybv.h"
#include "raygeom.h"
int IntersectBVs(geometry_under_test *pGTest, BV *pBV1,BV *pBV2)
{
intptr_t mask;
int iNode[2],*pUsedNodesMap[2],res=0,nullmap=0,bNodeUsed[2];
mask = iszero_mask(pGTest[0].pUsedNodesMap); // mask = -(pUsedNodeMap==0)
pUsedNodesMap[0] = (int*)((intptr_t)pGTest[0].pUsedNodesMap&~mask | (intptr_t)&nullmap&mask);
iNode[0] = pBV1->iNode&~mask;
mask = iszero_mask(pGTest[1].pUsedNodesMap); // mask = -(pUsedNodeMap==0)
pUsedNodesMap[1] = (int*)((intptr_t)pGTest[1].pUsedNodesMap&~mask | (intptr_t)&nullmap&mask);
iNode[1] = pBV2->iNode&~mask;
bNodeUsed[0] = pUsedNodesMap[0][iNode[0]>>5]>>(iNode[0]&31) & 1;
bNodeUsed[1] = pUsedNodesMap[1][iNode[1]>>5]>>(iNode[1]&31) & 1;
if (bNodeUsed[0] & bNodeUsed[1])
return 0; // skip check only if both nodes are marked used
//if (pUsedNodesMap[0][iNode[0]>>5] & 1<<(iNode[0]&31) | pUsedNodesMap[1][iNode[1]>>5] & 1<<(iNode[1]&31))
// return 0; // skip check if at least one BV node is marked checked
if (!g_Overlapper.Check(pBV1->type,pBV2->type, *pBV1,*pBV2))
return 0;
float split1,split2;
split1 = pGTest[0].pBVtree->SplitPriority(pBV1);
split2 = pGTest[1].pBVtree->SplitPriority(pBV2);
BV *pBV_split1,*pBV_split2;
if (split1>split2 && split1>0) { // split the first BV
pGTest[0].pBVtree->GetNodeChildrenBVs(pBV1, pBV_split1,pBV_split2);
res = IntersectBVs(pGTest, pBV_split1,pBV2);
if (pGTest[0].bStopIntersection + pGTest[1].bStopIntersection > 0)
return res;
res += IntersectBVs(pGTest, pBV_split2,pBV2);
pGTest[0].pBVtree->ReleaseLastBVs();
} else
if (split2>0) { // split the second BV
pGTest[1].pBVtree->GetNodeChildrenBVs(pGTest[1].R_rel,pGTest[1].offset_rel,pGTest[1].scale_rel, pBV2, pBV_split1,pBV_split2);
res = IntersectBVs(pGTest, pBV1,pBV_split1);
if (pGTest[0].bStopIntersection + pGTest[1].bStopIntersection > 0)
return res;
res += IntersectBVs(pGTest, pBV1,pBV_split2);
pGTest[1].pBVtree->ReleaseLastBVs();
} else {
int nPrims1,nPrims2,iClient,i,j;
primitive *ptr[2];
prim_inters inters;
static vectorf ptborder[16];
inters.minPtDist2 = sqr(min(pGTest[0].pGeometry->m_minVtxDist, pGTest[1].pGeometry->m_minVtxDist));
iClient = -(pGTest[1].pGeometry->m_iCollPriority-pGTest[0].pGeometry->m_iCollPriority>>31);
inters.pt[1].Set(0,0,0);
inters.ptborder = ptborder;
inters.nborderpt = inters.nBestPtVal = 0;
inters.nbordersz = sizeof(ptborder)/sizeof(ptborder[0]);
nPrims1 = pGTest[0].pBVtree->GetNodeContents(pBV1->iNode, pBV2,bNodeUsed[1],1, pGTest+0,pGTest+1);
nPrims2 = pGTest[1].pBVtree->GetNodeContents(pBV2->iNode, pBV1,bNodeUsed[0],0, pGTest+1,pGTest+0);
for(i=0,ptr[0]=pGTest[0].primbuf; i<nPrims1; i++,ptr[0]=(primitive*)((char*)ptr[0]+pGTest[0].szprim))
for(j=0,ptr[1]=pGTest[1].primbuf; j<nPrims2; j++,ptr[1]=(primitive*)((char*)ptr[1]+pGTest[1].szprim))
if (g_Intersector.Check(pGTest[iClient].typeprim,pGTest[iClient^1].typeprim, ptr[iClient],ptr[iClient^1], &inters))
{
inters.id[0] = pGTest[iClient].idbuf[i&-(iClient^1)|j&-iClient];
inters.id[1] = pGTest[iClient^1].idbuf[i&-iClient|j&-(iClient^1)];
inters.iNode[0] = pBV1->iNode;
inters.iNode[1] = pBV2->iNode;
pGTest[0].bCurNodeUsed = pGTest[1].bCurNodeUsed = 0;
res += pGTest[iClient].pGeometry->RegisterIntersection(ptr[iClient],ptr[iClient^1], pGTest+iClient,pGTest+(iClient^1), &inters);
if (pGTest[0].bStopIntersection+pGTest[1].bStopIntersection + pGTest[0].bCurNodeUsed+pGTest[1].bCurNodeUsed> 0)
return res;
inters.nborderpt = inters.nBestPtVal = 0;
inters.nbordersz = sizeof(ptborder)/sizeof(ptborder[0]);
}
}
return res;
}
int SweepTestBVs(geometry_under_test *pGTest, BV *pBV1,BV *pBV2)
{
if (!g_Overlapper.Check(pBV1->type,pBV2->type, *pBV1,*pBV2))
return 0;
int res = 0;
float split1,split2;
split1 = pGTest[0].pBVtree->SplitPriority(pBV1);
split2 = pGTest[1].pBVtree->SplitPriority(pBV2);
BV *pBV_split1,*pBV_split2;
if (split1>split2 && split1>0) { // split the first BV
pGTest[0].pBVtree->GetNodeChildrenBVs(pBV1, pGTest[0].sweepdir_loc,pGTest[0].sweepstep_loc, pBV_split1,pBV_split2);
res = SweepTestBVs(pGTest, pBV_split1,pBV2) + SweepTestBVs(pGTest, pBV_split2,pBV2);
pGTest[0].pBVtree->ReleaseLastSweptBVs();
} else
if (split2>0) { // split the second BV
pGTest[1].pBVtree->GetNodeChildrenBVs(pGTest[1].R_rel,pGTest[1].offset_rel,pGTest[1].scale_rel, pBV2, pBV_split1,pBV_split2);
res = SweepTestBVs(pGTest, pBV1,pBV_split1) + SweepTestBVs(pGTest, pBV1,pBV_split2);
pGTest[1].pBVtree->ReleaseLastBVs();
} else {
int nPrims1,nPrims2,i,j;
primitive *ptr[2];
contact contact_cur;
geom_contact *pcontact = pGTest[0].contacts;
unprojection_mode unproj;
vectorf startoffs = pGTest[0].offset;
pGTest[0].offset += pGTest[0].sweepdir*pGTest[0].sweepstep;
unproj.imode = 0;
unproj.dir = -pGTest[0].sweepdir;
unproj.tmax = pGTest[0].sweepstep;
unproj.minPtDist = min(pGTest[0].pGeometry->m_minVtxDist, pGTest[1].pGeometry->m_minVtxDist);
nPrims1 = pGTest[0].pBVtree->GetNodeContents(pBV1->iNode, pBV2,0,-1, pGTest+0,pGTest+1);
nPrims2 = pGTest[1].pBVtree->GetNodeContents(pBV2->iNode, pBV1,0,0, pGTest+1,pGTest+0);
for(i=0,ptr[0]=pGTest[0].primbuf; i<nPrims1; i++,ptr[0]=(primitive*)((char*)ptr[0]+pGTest[0].szprim))
for(j=0,ptr[1]=pGTest[1].primbuf; j<nPrims2; j++,ptr[1]=(primitive*)((char*)ptr[1]+pGTest[1].szprim))
if (g_Unprojector.Check(&unproj, pGTest[0].typeprim,pGTest[1].typeprim, ptr[0],-1,ptr[1],-1, &contact_cur) &&
contact_cur.n*pGTest[0].sweepdir>0 && contact_cur.t<=pGTest[0].sweepstep && pGTest[0].sweepstep-contact_cur.t<pcontact->t)
{
pcontact->t = pGTest[0].sweepstep-contact_cur.t;
pcontact->pt = contact_cur.pt;
pcontact->n = contact_cur.n.normalized();
pcontact->iFeature[0] = contact_cur.iFeature[0];
pcontact->iFeature[1] = contact_cur.iFeature[1];
pcontact->id[0] = pGTest[0].idbuf[i];
pcontact->id[1] = pGTest[1].idbuf[j];
pcontact->iNode[0] = pBV1->iNode;
pcontact->iNode[1] = pBV2->iNode;
res++; *(pGTest[0].pnContacts) = 1;
}
pGTest[0].offset = startoffs;
}
return res;
}
int CGeometry::Intersect(IGeometry *pCollider, geom_world_data *pdata1,geom_world_data *pdata2, intersection_params *pparams, geom_contact *&pcontacts)
{
FUNCTION_PROFILER( GetISystem(),PROFILE_PHYSICS );
geometry_under_test gtest[2];
geom_world_data *pdata[2] = { pdata1,pdata2 };
int i,j,jmax,mask,nContacts=0,iStartNode[2];
intersection_params defip;
vectorr offsetWorld;
if (!pparams)
pparams = &defip;
// zero all global buffer pointers
ResetGlobalPrimsBuffers();
g_Overlapper.Init();
if (!pparams->bKeepPrevContacts) {
g_nAreas = 0; g_nAreaPt = 0; g_nTotContacts = 0;
}
if (g_nTotContacts>=sizeof(g_Contacts)/sizeof(g_Contacts[0]))
return 0;
g_SurfaceDescBufPos = 0;
g_EdgeDescBufPos = 0;
g_IdBufPos = 0;
g_iFeatureBufPos = 0;
g_UsedNodesMapPos = 0;
g_UsedNodesIdxPos = 0;
pcontacts = g_Contacts+g_nTotContacts;
pparams->pGlobalContacts = g_Contacts;
if (!pparams->bNoAreaContacts && g_nAreas<sizeof(g_AreaBuf)/sizeof(g_AreaBuf[0]) && g_nAreaPt<sizeof(g_AreaPtBuf)/sizeof(g_AreaPtBuf[0])) {
pcontacts[0].parea = g_AreaBuf+g_nAreas;
pcontacts[0].parea->pt = g_AreaPtBuf+g_nAreaPt;
pcontacts[0].parea->piPrim[0] = g_AreaPrimBuf0+g_nAreaPt;
pcontacts[0].parea->piFeature[0] = g_AreaFeatureBuf0+g_nAreaPt;
pcontacts[0].parea->piPrim[1] = g_AreaPrimBuf1+g_nAreaPt;
pcontacts[0].parea->piFeature[1] = g_AreaFeatureBuf1+g_nAreaPt;
pcontacts[0].parea->npt = 0; pcontacts[0].parea->nmaxpt = sizeof(g_AreaPtBuf)/sizeof(g_AreaPtBuf[0])-g_nAreaPt;
/*for(i=0;i<pcontacts[0].parea->nmaxpt;i++) {
pcontacts[0].parea->piPrim[0][i]=pcontacts[0].parea->piFeature[0][i]=-2;
pcontacts[0].parea->pt[i](777.0f,777.0f,777.0f); }*/
pcontacts[0].parea->minedge = min(gtest[0].minAreaEdge, gtest[1].minAreaEdge);
} else
pcontacts[0].parea = 0;
if (pparams->bSweepTest && pdata1->v.len2()==0) {
pparams->bSweepTest = 0; pdata1->v.Set(0,0,1); pparams->vrel_min = 0;
}
for(i=0;i<2;i++) {
if (pdata[i]) {
gtest[i].offset = pdata[i]->offset;
gtest[i].R = pdata[i]->R;
gtest[i].scale = pdata[i]->scale;
gtest[i].rscale = 1.0f/pdata[i]->scale;
gtest[i].v = pdata[i]->v;
gtest[i].w = pdata[i]->w;
gtest[i].centerOfMass = pdata[i]->centerOfMass;
iStartNode[i] = pdata[i]->iStartNode;
} else {
gtest[i].offset.Set(0,0,0);
gtest[i].R.SetIdentity();
gtest[i].scale = gtest[i].rscale = 1.0f;
gtest[i].v.Set(0,0,0);
gtest[i].w.Set(0,0,0);
iStartNode[i] = 0;
}
gtest[i].centerOfRotation = pparams->centerOfRotation;
gtest[i].axisContactNormal = pparams->axisContactNormal*(1-(i<<1));
gtest[i].contacts = pcontacts;
gtest[i].pnContacts = &nContacts;
gtest[i].nMaxContacts = sizeof(g_Contacts)/sizeof(g_Contacts[0])-g_nTotContacts;
gtest[i].bStopIntersection = 0;
gtest[i].sweepstep = 0;
gtest[i].ptOutsidePivot = pparams->ptOutsidePivot[i];
gtest[i].pParams = pparams;
}
for(i=0;i<2;i++) {
gtest[i].offset_rel = ((gtest[i].offset-gtest[i^1].offset)*gtest[i^1].R)*gtest[i^1].rscale;
(gtest[i].R_rel = gtest[i^1].R.T()) *= gtest[i].R;
gtest[i].scale_rel = gtest[i].scale*gtest[i^1].rscale;
gtest[i].rscale_rel = gtest[i^1].scale*gtest[i].rscale;
}
pparams->bBothConvex = m_bIsConvex & ((CGeometry*)pCollider)->m_bIsConvex;
gtest[0].offset -= (offsetWorld = gtest[1].offset);
gtest[0].centerOfMass -= offsetWorld; gtest[0].centerOfRotation -= offsetWorld; gtest[0].ptOutsidePivot -= offsetWorld;
gtest[1].centerOfMass -= offsetWorld; gtest[1].centerOfRotation -= offsetWorld; gtest[1].ptOutsidePivot -= offsetWorld;
gtest[1].offset.zero(); // use relative offset in calculations to improve accuracy
BV *pBV1,*pBV2;
if (!pparams->bSweepTest) {
if (!PrepareForIntersectionTest(gtest+0, (CGeometry*)pCollider,gtest+1, pparams->bKeepPrevContacts) ||
!((CGeometry*)pCollider)->PrepareForIntersectionTest(gtest+1, this,gtest+0, pparams->bKeepPrevContacts))
return 0;
if (iStartNode[0]+iStartNode[1]) {
gtest[0].pBVtree->GetNodeBV(pBV1, iStartNode[0]);
gtest[1].pBVtree->GetNodeBV(gtest[1].R_rel,gtest[1].offset_rel,gtest[1].scale_rel, pBV2, iStartNode[1]);
IntersectBVs(gtest, pBV1,pBV2);
}
if (nContacts==0) {
gtest[0].pBVtree->GetNodeBV(pBV1);
gtest[1].pBVtree->GetNodeBV(gtest[1].R_rel,gtest[1].offset_rel,gtest[1].scale_rel, pBV2);
IntersectBVs(gtest, pBV1,pBV2);
}
int iClient = -(gtest[1].pGeometry->m_iCollPriority-gtest[0].pGeometry->m_iCollPriority>>31);
if (iClient) for(i=0;i<nContacts;i++) {
if (pcontacts[i].parea && pcontacts[i].parea->npt) {
vectorf ntmp=pcontacts[i].n; pcontacts[i].n=pcontacts[i].parea->n1; pcontacts[i].parea->n1=ntmp;
int *pprim=pcontacts[i].parea->piPrim[0]; pcontacts[i].parea->piPrim[0]=pcontacts[i].parea->piPrim[1]; pcontacts[i].parea->piPrim[1]=pprim;
int *pfeat=pcontacts[i].parea->piFeature[0]; pcontacts[i].parea->piFeature[0]=pcontacts[i].parea->piFeature[1];
pcontacts[i].parea->piFeature[1]=pfeat;
if (pcontacts[i].iUnprojMode) {
pcontacts[i].n = pcontacts[i].n.rotated(pcontacts[i].dir,-pcontacts[i].t);
pcontacts[i].parea->n1 = pcontacts[i].parea->n1.rotated(pcontacts[i].dir,-pcontacts[i].t);
}
if (pcontacts[i].iUnprojMode) for(j=0;j<pcontacts[i].parea->npt;j++)
pcontacts[i].parea->pt[j] = pcontacts[i].parea->pt[j].rotated(gtest[0].centerOfRotation,pcontacts[i].dir,-pcontacts[i].t);
else for(j=0;j<pcontacts[i].parea->npt;j++)
pcontacts[i].parea->pt[j] -= pcontacts[i].dir*pcontacts[i].t;
} else {
if (pcontacts[i].iUnprojMode)
pcontacts[i].n = pcontacts[i].n.rotated(pcontacts[i].dir,-pcontacts[i].t);
pcontacts[i].n.Flip();
}
if (pcontacts[i].iUnprojMode)
pcontacts[i].pt = pcontacts[i].pt.rotated(gtest[0].centerOfRotation,pcontacts[i].dir,-pcontacts[i].t);
else
pcontacts[i].pt -= pcontacts[i].dir*pcontacts[i].t;
pcontacts[i].dir.Flip();
short id=pcontacts[i].id[0]; pcontacts[i].id[0]=pcontacts[i].id[1]; pcontacts[i].id[1]=id;
int iprim=pcontacts[i].iPrim[0]; pcontacts[i].iPrim[0]=pcontacts[i].iPrim[1]; pcontacts[i].iPrim[1]=iprim;
int ifeature=pcontacts[i].iFeature[0]; pcontacts[i].iFeature[0]=pcontacts[i].iFeature[1]; pcontacts[i].iFeature[1]=ifeature;
}
// sort contacts in descending t order
geom_contact tmpcontact;
for(i=0;i<nContacts-1;i++) {
for(jmax=i,j=i+1; j<nContacts; j++) {
mask = -isneg(pcontacts[jmax].t-pcontacts[j].t);
jmax = jmax&~mask | j&mask;
}
if (jmax!=i) {
if (pcontacts[i].ptborder==&pcontacts[i].center) pcontacts[i].ptborder = &pcontacts[jmax].center;
if (pcontacts[i].ptborder==&pcontacts[i].pt) pcontacts[i].ptborder = &pcontacts[jmax].pt;
if (pcontacts[jmax].ptborder==&pcontacts[jmax].center) pcontacts[jmax].ptborder = &pcontacts[i].center;
if (pcontacts[jmax].ptborder==&pcontacts[jmax].pt) pcontacts[jmax].ptborder = &pcontacts[i].pt;
tmpcontact=pcontacts[i]; pcontacts[i]=pcontacts[jmax]; pcontacts[jmax]=tmpcontact;
}
}
} else {
gtest[0].sweepstep = pcontacts[0].vel = gtest[0].v.len();
gtest[0].sweepdir = gtest[0].v/gtest[0].sweepstep;
gtest[0].sweepstep *= pparams->time_interval;
gtest[0].sweepdir_loc = gtest[0].sweepdir*gtest[0].R;
gtest[0].sweepstep_loc = gtest[0].sweepstep*gtest[0].rscale;
if (!PrepareForIntersectionTest(gtest+0, (CGeometry*)pCollider,gtest+1, pparams->bKeepPrevContacts) ||
!((CGeometry*)pCollider)->PrepareForIntersectionTest(gtest+1, this,gtest+0, pparams->bKeepPrevContacts))
return 0;
pcontacts[0].ptborder = &g_Contacts[0].pt;
pcontacts[0].nborderpt = 1;
pcontacts[0].parea = 0;
pcontacts[0].dir = -gtest[0].sweepdir;
pcontacts[0].t = gtest[0].sweepstep;
gtest[0].pBVtree->GetNodeBV(pBV1, gtest[0].sweepdir_loc,gtest[0].sweepstep_loc);
gtest[1].pBVtree->GetNodeBV(gtest[1].R_rel,gtest[1].offset_rel,gtest[1].scale_rel, pBV2);
SweepTestBVs(gtest, pBV1,pBV2);
}
for(i=0;i<nContacts;i++) {
pcontacts[i].pt += offsetWorld;
pcontacts[i].center += offsetWorld;
if (pcontacts[i].ptborder!=&pcontacts[i].pt && pcontacts[i].ptborder!=&pcontacts[i].center)
for(j=0;j<pcontacts[i].nborderpt;j++)
pcontacts[i].ptborder[j] += offsetWorld;
if (pcontacts[i].parea) for(j=0;j<pcontacts[i].parea->npt;j++)
pcontacts[i].parea->pt[j] += offsetWorld;
}
CleanupAfterIntersectionTest(gtest+0);
((CGeometry*)pCollider)->CleanupAfterIntersectionTest(gtest+1);
g_nTotContacts += nContacts;
return nContacts;
}
int CGeometry::RegisterIntersection(primitive *pprim1,primitive *pprim2, geometry_under_test *pGTest1,geometry_under_test *pGTest2,
prim_inters *pinters)
{
unprojection_mode unproj;
contact contact_cur;
geom_contact *pres = pGTest1->contacts + *pGTest1->pnContacts;
primitive *pprims[2] = { pprim1, pprim2 };
pres->ptborder = &pres->pt;
pres->nborderpt = 1;
if (pGTest1->pParams->iUnprojectionMode==0) {
// for linear unprojection, find point with maximum relative normal velocity
unproj.imode = 0;
unproj.dir = pGTest2->v+(pGTest2->w^pinters->pt[1]-pGTest2->centerOfMass) -
pGTest1->v-(pGTest1->w^pinters->pt[1]-pGTest1->centerOfMass);
unproj.vel = unproj.dir.len();
if (unproj.vel < pGTest1->pParams->vrel_min)
goto use_normal;
unproj.dir /= unproj.vel;
} else if (pGTest1->pParams->iUnprojectionMode==1) {
unproj.imode = 1;
unproj.dir = pGTest2->w-pGTest1->w;
unproj.center = pGTest1->centerOfRotation.len2()>pGTest2->centerOfRotation.len2() ? pGTest1->centerOfRotation : pGTest2->centerOfRotation;
unproj.vel = unproj.dir.len();
unproj.dir /= unproj.vel;
}
unproj.tmax = pGTest1->pParams->time_interval*unproj.vel;
if (!g_Unprojector.Check(&unproj, pGTest1->typeprim,pGTest2->typeprim, pprims[0],-1,pprims[1],-1, &contact_cur, pres->parea))
return 0;
if (contact_cur.t > pGTest1->pParams->time_interval*unproj.vel) {
use_normal:
unproj.imode = 0;
unproj.dir = pinters->n.normalize();
unproj.vel = 0;
if (!g_Unprojector.Check(&unproj, pGTest1->typeprim,pGTest2->typeprim, pprims[0],-1,pprims[1],-1, &contact_cur, pres->parea))
return 0;
}
pres->t = contact_cur.t;
pres->pt = contact_cur.pt;
pres->n = contact_cur.n;
pres->dir = unproj.dir;
pres->vel = unproj.vel;
pres->iUnprojMode = unproj.imode;
pres->id[0] = pinters->id[0];
pres->id[1] = pinters->id[1];
pres->iNode[0] = pinters->iNode[0];
pres->iNode[1] = pinters->iNode[1];
if (pres->parea->npt>0) {
g_nAreaPt += pres->parea->npt;
g_nAreas++;
} else
pres->parea = 0;
// allocate slots for the next intersection
(*pGTest1->pnContacts)++;
pres = pGTest1->contacts + *pGTest1->pnContacts;
if (g_nAreas<sizeof(g_AreaBuf)/sizeof(g_AreaBuf[0]) && g_nAreaPt<sizeof(g_AreaPtBuf)/sizeof(g_AreaPtBuf[0])) {
pres->parea = g_AreaBuf+g_nAreas;
pres->parea->pt = g_AreaPtBuf+g_nAreaPt;
pres->parea->piPrim[0] = g_AreaPrimBuf0+g_nAreaPt; pres->parea->piFeature[0] = g_AreaFeatureBuf0+g_nAreaPt;
pres->parea->piPrim[1] = g_AreaPrimBuf1+g_nAreaPt; pres->parea->piFeature[1] = g_AreaFeatureBuf1+g_nAreaPt;
pres->parea->npt = 0; pres->parea->nmaxpt = sizeof(g_AreaPtBuf)/sizeof(g_AreaPtBuf[0])-g_nAreaPt;
pres->parea->minedge = min(pGTest1->minAreaEdge, pGTest2->minAreaEdge);
} else
pres->parea = 0;
if (*pGTest1->pnContacts >= pGTest1->nMaxContacts)
pGTest1->bStopIntersection = 1;
return 0;
}
struct radius_check_data {
CGeometry *pGeom;
CBVTree *pBVtree;
geom_world_data *pgwd;
sphere sph;
float rmin,rmax;
float zscale;
int **pGrid;
int nRes;
int nGrow;
int iPass;
};
int RadiusCheckBVs(radius_check_data *prcd, BV *pBV)
{
if (!g_Overlapper.Check(pBV->type,sphere::type, *pBV,&prcd->sph))
return 0;
if (prcd->pBVtree->SplitPriority(pBV)>0) {
BV *pBV_split1,*pBV_split2;
prcd->pBVtree->GetNodeChildrenBVs(pBV, pBV_split1,pBV_split2);
int res = RadiusCheckBVs(prcd, pBV_split1)+RadiusCheckBVs(prcd, pBV_split2);
prcd->pBVtree->ReleaseLastBVs();
return res;
} else {
int iStartPrim,nPrims;
nPrims = prcd->pBVtree->GetNodeContentsIdx(pBV->iNode, iStartPrim);
return prcd->pGeom->DrawToOcclusionCubemap(prcd->pgwd, iStartPrim,nPrims, prcd->iPass,
prcd->pGrid,prcd->nRes, prcd->rmin,prcd->rmax,prcd->zscale);
}
}
float CGeometry::BuildOcclusionCubemap(geom_world_data *pgwd, int iMode, int *pGrid0[6],int *pGrid1[6],int nRes, float rmin,float rmax, int nGrow)
{
radius_check_data rcd;
float rscale = pgwd->scale==1.0f ? 1.0f:1.0f/pgwd->scale;
int i,j,irmin;
ResetGlobalPrimsBuffers();
rcd.pgwd = pgwd;
rcd.sph.center = (-pgwd->offset*rscale)*pgwd->R;
rcd.sph.r = rmax*rscale;
rcd.rmin = rmin;
rcd.rmax = rmax;
rcd.zscale = 65535.0f/rmax;
rcd.nRes = nRes;
rcd.nGrow = nGrow;
rcd.iPass = 0;
if (iMode==0)
rcd.pGrid = pGrid0;
else {
rcd.pGrid = pGrid1;
for(i=0;i<6;i++) for(j=nRes*nRes-1;j>=0;j--)
pGrid1[i][j] = (1u<<31)-1;
}
rcd.pGeom = this;
rcd.pBVtree = GetBVTree();
BV *pBV;
rcd.pBVtree->GetNodeBV(pBV);
if (RadiusCheckBVs(&rcd,pBV)) {// && iMode==0) {
rcd.iPass = 1;
ResetGlobalPrimsBuffers();
RadiusCheckBVs(&rcd,pBV);
}
irmin = float2int(rmin*rcd.zscale);
for(i=0;i<6;i++) for(j=nRes*nRes-1;j>=0;j--) // if the highest bit is set, change cell z to irmin
rcd.pGrid[i][j] = irmin&rcd.pGrid[i][j]>>31 | rcd.pGrid[i][j]&~(rcd.pGrid[i][j]>>31);
if (iMode) {
int nCells,nOccludedCells;
GrowAndCompareCubemaps(pGrid0,pGrid1,nRes, nGrow, nCells,nOccludedCells);
return nCells>0 ? (float)(nCells-nOccludedCells)/nCells : 0.0f;
}
return 0.0f;
}
void DrawBBox(void (*DrawLineFunc)(float*,float*), geom_world_data *gwd, CBVTree *pTree,BBox *pbbox,int maxlevel,int level)
{
if (level<maxlevel && pTree->SplitPriority(pbbox)>0) {
BV *pbbox1,*pbbox2;
pTree->GetNodeChildrenBVs(gwd->R,gwd->offset,gwd->scale, pbbox, pbbox1,pbbox2);
DrawBBox(DrawLineFunc,gwd, pTree,(BBox*)pbbox1,maxlevel,level+1);
DrawBBox(DrawLineFunc,gwd, pTree,(BBox*)pbbox2,maxlevel,level+1);
pTree->ReleaseLastBVs();
return;
}
vectorf pts[8],sz;
int i,j;
for(i=0;i<8;i++) {
for(j=0;j<3;j++) sz[j]=pbbox->abox.size[j]*(((i>>j&1)<<1)-1);
pts[i] = pbbox->abox.Basis.T()*sz + pbbox->abox.center;
}
for(i=0;i<8;i++) for(j=0;j<3;j++) if (i&1<<j)
DrawLineFunc(pts[i],pts[i^1<<j]);
}
int CPrimitive::Intersect(IGeometry *_pCollider, geom_world_data *pdata1,geom_world_data *pdata2,
intersection_params *pparams, geom_contact *&pcontacts)
{
CGeometry *pCollider = (CGeometry*)_pCollider;
if (!pCollider->IsAPrimitive())
return CGeometry::Intersect(pCollider,pdata1,pdata2,pparams,pcontacts);
FUNCTION_PROFILER( GetISystem(),PROFILE_PHYSICS );
static geom_world_data defgwd;
static intersection_params defip;
pdata1 = (geom_world_data*)((intptr_t)pdata1 | -iszero((intptr_t)pdata1) & (intptr_t)&defgwd);
pdata2 = (geom_world_data*)((intptr_t)pdata2 | -iszero((intptr_t)pdata2) & (intptr_t)&defgwd);
pparams = (intersection_params*)((intptr_t)pparams | -iszero((intptr_t)pparams) & (intptr_t)&defip);
if (!pparams->bKeepPrevContacts)
g_nAreas = g_nAreaPt = g_nTotContacts = g_BrdPtBufPos = 0;
if (g_nTotContacts>=sizeof(g_Contacts)/sizeof(g_Contacts[0]))
return 0;
pcontacts = g_Contacts+g_nTotContacts;
pcontacts->ptborder = g_BrdPtBuf+g_BrdPtBufPos;
pcontacts->nborderpt = 0;
pparams->pGlobalContacts = g_Contacts;
BV *pBV1,*pBV2;
prim_inters inters;
vectorf sweepdir(zero); float sweepstep=0;
ResetGlobalPrimsBuffers();
g_Overlapper.Init();
if (!pparams->bSweepTest)
GetBVTree()->GetNodeBV(pdata1->R,pdata1->offset,pdata1->scale, pBV1);
else {
sweepstep = pdata1->v.len();
sweepdir = pdata1->v/sweepstep;
sweepstep *= pparams->time_interval;
GetBVTree()->GetNodeBV(pdata1->R,pdata1->offset,pdata1->scale, pBV1, sweepdir,sweepstep);
}
pCollider->GetBVTree()->GetNodeBV(pdata2->R,pdata2->offset,pdata2->scale, pBV2);
if (!g_Overlapper.Check(pBV1->type,pBV2->type, *pBV1,*pBV2))
return 0;
// get primitives in world space
int i,itype[2],bUnprojected=0;
primitive *pprim[2];
pdata1->offset += sweepdir*sweepstep;
itype[0] = PreparePrimitive(pdata1,pprim[0]);
itype[1] = pCollider->PreparePrimitive(pdata2,pprim[1]);
pdata1->offset -= sweepdir*sweepstep;
if (pCollider->m_iCollPriority==0) { // probably the other geometry is a ray
if (!g_Intersector.Check(itype[0],itype[1], pprim[0],pprim[1], &inters))
return 0;
geometry_under_test gtest;
gtest.contacts = g_Contacts+g_nTotContacts;
gtest.pnContacts = &g_nTotContacts;
gtest.pParams = pparams;
pCollider->RegisterIntersection(pprim[0],pprim[1],&gtest,0,&inters);
pcontacts->n.Flip();
return 1;
}
unprojection_mode unproj;
contact contact_best;
contact_best.t = 0;
geom_contact_area *parea;
unproj.minPtDist = min(m_minVtxDist,pCollider->m_minVtxDist);
if (!pparams->bNoAreaContacts && g_nAreas<sizeof(g_AreaBuf)/sizeof(g_AreaBuf[0]) && g_nAreaPt<sizeof(g_AreaPtBuf)/sizeof(g_AreaPtBuf[0])) {
parea = g_AreaBuf+g_nAreas;
parea->pt = g_AreaPtBuf+g_nAreaPt;
parea->piPrim[0] = g_AreaPrimBuf0+g_nAreaPt;
parea->piFeature[0] = g_AreaFeatureBuf0+g_nAreaPt;
parea->piPrim[1] = g_AreaPrimBuf1+g_nAreaPt;
parea->piFeature[1] = g_AreaFeatureBuf1+g_nAreaPt;
parea->npt = 0; parea->nmaxpt = sizeof(g_AreaPtBuf)/sizeof(g_AreaPtBuf[0])-g_nAreaPt;
parea->minedge = 0;
} else
parea = 0;
if (!pparams->bSweepTest) {
vectorf ptm;
if (!pparams->bNoIntersection) {
if (g_Intersector.CheckExists(itype[0],itype[1])) {
inters.ptborder = pcontacts->ptborder;
inters.nborderpt = 0;
if (!g_Intersector.Check(itype[0],itype[1], pprim[0],pprim[1], &inters))
return 0;
ptm = inters.ptborder[0];
pcontacts->nborderpt = inters.nborderpt;
for(i=0,pcontacts->center.zero();i<inters.nborderpt;i++) pcontacts->center += pcontacts->ptborder[i];
pcontacts->center /= inters.nborderpt;
}
} else if (!g_Overlapper.Check(itype[0],itype[1], pprim[0],pprim[1]))
return 0;
if (pparams->iUnprojectionMode==0) {
if (pparams->vrel_min<1E9f) {
vectorf vrel;
if (!pcontacts->nborderpt) {
vectorf center[2],pt[3]; box bbox;
int iPrim,iFeature; // dummy parameters
if (pBV1->type==box::type) center[0] = ((box*)(primitive*)*pBV1)->center;
else { GetBBox(&bbox); center[0] = pdata1->R*bbox.center+pdata1->offset; }
if (pBV1->type==box::type) center[1] = ((box*)(primitive*)*pBV2)->center;
else { pCollider->GetBBox(&bbox); center[1] = pdata2->R*bbox.center+pdata2->offset; }
FindClosestPoint(pdata1,iPrim,iFeature,center[1],center[1],pt+0);
pCollider->FindClosestPoint(pdata2,iPrim,iFeature,center[0],center[0],pt+1);
if (pCollider->PointInsideStatus(((pt[0]-pdata2->offset)*pdata2->R)*(pdata2->scale==1.0f ? 1.0f:1.0f/pdata2->scale)))
ptm = pt[0];
else if (PointInsideStatus(((pt[1]-pdata1->offset)*pdata1->R)*(pdata1->scale==1.0f ? 1.0f:1.0f/pdata1->scale)))
ptm = pt[1];
else
ptm = (pt[0]+pt[1])*0.5f;
}
vrel = pdata1->v+(pdata1->w^ptm-pdata1->centerOfMass)-pdata2->v-(pdata2->w^ptm-pdata2->centerOfMass);
if (vrel.len2()>sqr(pparams->vrel_min)) {
unproj.imode = 0; // unproject along vrel
(unproj.dir=-vrel) /= (unproj.vel=vrel.len());
unproj.tmax = pparams->time_interval*unproj.vel;
bUnprojected = g_Unprojector.Check(&unproj, itype[0],itype[1], pprim[0],-1,pprim[1],-1, &contact_best, parea);
bUnprojected &= isneg(contact_best.t-unproj.tmax);
}
}
} else {
unproj.imode = 1;
unproj.center = pparams->centerOfRotation;
if (pparams->axisOfRotation.len2()==0) {
unproj.dir = inters.n^inters.pt[0]-unproj.center;
if (unproj.dir.len2()<1E-6f)
unproj.dir = GetOrthogonal(inters.n);
unproj.dir.normalize();
} else
unproj.dir = pparams->axisOfRotation;
bUnprojected = g_Unprojector.Check(&unproj, itype[0],itype[1], pprim[0],-1,pprim[1],-1, &contact_best, parea);
if (bUnprojected)
contact_best.t = atan2(contact_best.t,contact_best.taux);
}
if (!bUnprojected) {
unproj.imode = 0;
unproj.dir.zero(); // zero requested direction - means minimum direction will be found
unproj.vel = 0; unproj.tmax = pparams->maxUnproj;
bUnprojected = g_Unprojector.Check(&unproj, itype[0],itype[1], pprim[0],-1,pprim[1],-1, &contact_best, parea);
}
} else {
unproj.imode = 0;
unproj.dir = -sweepdir;
unproj.tmax = sweepstep;
unproj.bCheckContact = 1;
contact_best.t = 0;
bUnprojected = g_Unprojector.Check(&unproj, itype[0],itype[1], pprim[0],-1,pprim[1],-1, &contact_best, parea);
bUnprojected &= isneg(contact_best.t-unproj.tmax);
if (bUnprojected && contact_best.n*unproj.dir>0) {
// if we hit something with the back side, 1st primitive probably just passed through the 2nd one,
// so move a little deeper than the contact and unproject again (some primitives check for minimal separating
// unprojection, and some - for maximum contacting; the former can cause this)
real t = contact_best.t;
box bbox; pCollider->GetBBox(&bbox);
vectorf dirloc,dirsz;
dirloc = bbox.Basis*(sweepdir*pdata2->R);
dirsz(fabs_tpl(dirloc.x)*bbox.size.y*bbox.size.z, fabs_tpl(dirloc.y)*bbox.size.x*bbox.size.z, fabs_tpl(dirloc.z)*bbox.size.x*bbox.size.y);
i = idxmax3((float*)&dirsz);
t += bbox.size[i]/fabs_tpl(dirloc[i])*0.1f;
unproj.tmax = sweepstep-t;
pdata1->offset += sweepdir*unproj.tmax;
itype[0] = PreparePrimitive(pdata1,pprim[0]);
pdata1->offset -= sweepdir*unproj.tmax;
bUnprojected = g_Unprojector.Check(&unproj, itype[0],itype[1], pprim[0],-1,pprim[1],-1, &contact_best, parea);
bUnprojected &= isneg(contact_best.t-unproj.tmax) & isneg(contact_best.n*unproj.dir);
contact_best.t += t;
unproj.tmax = sweepstep;
}
}
if (bUnprojected) {
pcontacts->t = contact_best.t;
if (pparams->bSweepTest)
pcontacts->t = unproj.tmax-pcontacts->t;
pcontacts->pt = contact_best.pt;
pcontacts->n = contact_best.n.normalized();
pcontacts->dir = unproj.dir;
pcontacts->iUnprojMode = unproj.imode;
pcontacts->vel = unproj.vel;
pcontacts->id[0] = pcontacts->id[1] = -1;
pcontacts->iPrim[0] = pcontacts->iPrim[1] = 0;
pcontacts->iFeature[0] = contact_best.iFeature[0];
pcontacts->iFeature[1] = contact_best.iFeature[1];
pcontacts->iNode[0] = pcontacts->iNode[1] = 0;
if (!parea || parea->npt==0)
pcontacts->parea = 0;
else {
pcontacts->parea = parea;
g_nAreas++; g_nAreaPt += parea->npt;
if (pcontacts->nborderpt<parea->npt && (pcontacts->nborderpt==0 || (iszero(itype[0]-cylinder::type) | iszero(itype[1]-cylinder::type)))) {
pcontacts->ptborder = parea->pt;
pcontacts->nborderpt = parea->npt;
for(i=0,pcontacts->center.zero(); i<parea->npt; i++) pcontacts->center += parea->pt[i];
pcontacts->center /= parea->npt;
}
}
if (pcontacts->nborderpt==0) {
pcontacts->ptborder[0]=pcontacts->center = pcontacts->pt;
pcontacts->nborderpt = 1;
}
pcontacts->bBorderConsecutive = false;
g_nTotContacts++;
g_BrdPtBufPos += pcontacts->nborderpt;
}
return bUnprojected;
}

96
CryPhysics/geometry.h Normal file
View File

@@ -0,0 +1,96 @@
#ifndef geometry_h
#define geometry_h
#pragma once
extern surface_desc g_SurfaceDescBuf[64];
extern int g_SurfaceDescBufPos;
extern edge_desc g_EdgeDescBuf[64];
extern int g_EdgeDescBufPos;
extern int g_iFeatureBuf[64];
extern int g_iFeatureBufPos;
extern short g_IdBuf[256];
extern int g_IdBufPos;
extern int g_UsedNodesMap[8192];
extern int g_UsedNodesMapPos;
extern int g_UsedNodesIdx[64];
extern int g_UsedNodesIdxPos;
extern geom_contact g_Contacts[64];
extern int g_nTotContacts;
extern geom_contact_area g_AreaBuf[32];
extern int g_nAreas;
extern vectorf g_AreaPtBuf[256];
extern int g_AreaPrimBuf0[256],g_AreaFeatureBuf0[256],g_AreaPrimBuf1[256],g_AreaFeatureBuf1[256];
extern int g_nAreaPt;
class CGeometry : public IGeometry {
public:
CGeometry() { m_bIsConvex=0; }
virtual ~CGeometry() {}
virtual int GetType() = 0;
virtual void Release() { delete this; }
virtual void GetBBox(box *pbox) = 0;
virtual int Intersect(IGeometry *pCollider, geom_world_data *pdata1,geom_world_data *pdata2, intersection_params *pparams, geom_contact *&pcontacts);
virtual int CalcPhysicalProperties(phys_geometry *pgeom) { return 0; }
virtual int FindClosestPoint(geom_world_data *pgwd, int &iPrim,int &iFeature, const vectorf &ptdst0,const vectorf &ptdst1,
vectorf *ptres, int nMaxIters=10) { return 0; }
virtual int PointInsideStatus(const vectorf &pt) { return -1; }
virtual void DrawWireframe(void (*DrawLineFunc)(float*,float*), geom_world_data *gwd, int iLevel) {}
virtual void CalcVolumetricPressure(geom_world_data *gwd, const vectorf &epicenter,float k,float rmin,
const vectorf &centerOfMass, vectorf &P,vectorf &L) {}
virtual float CalculateBuoyancy(const plane *pplane, const geom_world_data *pgwd, vectorf &massCenter) { massCenter.zero(); return 0; }
virtual void CalculateMediumResistance(const plane *pplane, const geom_world_data *pgwd, vectorf &dPres,vectorf &dLres) { dPres.zero(); dLres.zero(); }
virtual int GetPrimitiveId(int iPrim,int iFeature) { return -1; }
virtual int IsConvex(float tolerance) { return 1; }
virtual void PrepareForRayTest(float raylen) {}
virtual CBVTree *GetBVTree() { return 0; }
virtual int GetPrimitiveCount() { return 1; }
virtual int IsAPrimitive() { return 0; }
virtual int PreparePrimitive(geom_world_data *pgwd,primitive *&pprim) { return -1; }
virtual int GetFeature(int iPrim,int iFeature, vectorf *pt) { return 0; }
virtual void RemapFaceIds(short *pMap,int sz) {}
virtual int UnprojectSphere(vectorf center,float r,float rsep, contact *pcontact) { return 0; }
virtual float BuildOcclusionCubemap(geom_world_data *pgwd, int iMode, int *pGrid0[6],int *pGrid1[6],int nRes, float rmin,float rmax, int nGrow);
virtual int DrawToOcclusionCubemap(const geom_world_data *pgwd, int iStartPrim,int nPrims, int iPass, int *pGrid[6],int nRes,
float rmin,float rmax,float zscale) { return 0; }
virtual void GetMemoryStatistics(ICrySizer *pSizer) {}
virtual void Save(CMemStream &stm) {}
virtual void Load(CMemStream &stm) {}
virtual int PrepareForIntersectionTest(geometry_under_test *pGTest, CGeometry *pCollider,geometry_under_test *pGTestColl, bool bKeepPrevContacts=false)
{ return 1; };
virtual int RegisterIntersection(primitive *pprim1,primitive *pprim2, geometry_under_test *pGTest1,geometry_under_test *pGTest2,
prim_inters *pinters);
virtual void CleanupAfterIntersectionTest(geometry_under_test *pGTest) {}
virtual int GetPrimitiveList(int iStart,int nPrims, int typeCollider,primitive *pCollider,int bColliderLocal, geometry_under_test *pGTest,
geometry_under_test *pGTestOp, primitive *pRes,short *pResId) { return 0; }
virtual int GetUnprojectionCandidates(int iop,const contact *pcontact, primitive *&pprim,int *&piFeature, geometry_under_test *pGTest) { return 0; }
virtual int PreparePolygon(coord_plane *psurface, int iPrim,int iFeature, geometry_under_test *pGTest, vector2df *&ptbuf,
int *&pVtxIdBuf,int *&pEdgeIdBuf) { return 0; }
virtual int PreparePolyline(coord_plane *psurface, int iPrim,int iFeature, geometry_under_test *pGTest, vector2df *&ptbuf,
int *&pVtxIdBuf,int *&pEdgeIdBuf) { return 0; }
float m_minVtxDist;
int m_iCollPriority;
int m_bIsConvex;
};
class CPrimitive : public CGeometry {
public:
CPrimitive() { m_bIsConvex=1; }
virtual int Intersect(IGeometry *pCollider, geom_world_data *pdata1,geom_world_data *pdata2, intersection_params *pparams, geom_contact *&pcontacts);
virtual int IsAPrimitive() { return 1; }
};
void DrawBBox(void (*DrawLineFunc)(float*,float*), geom_world_data *gwd, CBVTree *pTree,BBox *pbbox,int maxlevel,int level=0);
#endif

45
CryPhysics/grid.h Normal file
View File

@@ -0,0 +1,45 @@
//////////////////////////////////////////////////////////////////////
//
// Grid
//
// File: grid.h
// Description : Grid class declaration and inlined implementation
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#ifndef grid_h
#define grid_h
#pragma once
#include "vector3d.h"
#include "vector2d.h"
struct grid {
vector_tpl<int> ax;
vectorf org;
vector2df step,stepr;
vector2d_tpl<unsigned int> sz;
float parity;
float scale;
unsigned short *pflags;
unsigned short holeflag;
int holepower;
int inrange(unsigned int ix, unsigned int iy) {
return ix<sz.x && iy<sz.y;
}
int inrange(int ix, int iy) {
return (unsigned int)ix<sz.x && (unsigned int)iy<sz.y;
}
int getcell(unsigned int ix, unsigned int iy) {
return ix<sz.x && iy<sz.y ? iy*sz.x+ix : sz.x*sz.y;
}
int getcell(int ix,int iy) {
return (unsigned int)ix<sz.x && (unsigned int)iy<sz.y ? iy*sz.x+ix : sz.x*sz.y;
}
};
#endif

View File

@@ -0,0 +1,131 @@
#include "stdafx.h"
#include "utils.h"
#include "primitives.h"
#include "bvtree.h"
#include "geometry.h"
#include "trimesh.h"
#include "heightfieldbv.h"
BVheightfield CHeightfieldBV::g_BVhf;
struct InitHeightfieldGlobals {
InitHeightfieldGlobals() {
CHeightfieldBV::g_BVhf.iNode = 0;
CHeightfieldBV::g_BVhf.type = heightfield::type;
}
};
static InitHeightfieldGlobals now;
float CHeightfieldBV::Build(CGeometry *pGeom)
{
m_pMesh = (CTriMesh*)pGeom;
return (m_phf->size.x*m_phf->step.x*m_phf->size.y*m_phf->step.y*(m_maxHeight-m_minHeight));
}
void CHeightfieldBV::SetHeightfield(heightfield *phf)
{
m_phf = phf;
m_PatchStart.set(0,0);
m_PatchSize = m_phf->size;
m_minHeight = -1;
m_maxHeight = 1;
}
void CHeightfieldBV::GetBBox(box *pbox)
{
pbox->size.x = m_PatchSize.x*m_phf->step.x*0.5f;
pbox->size.y = m_PatchSize.y*m_phf->step.y*0.5f;
pbox->size.z = (m_maxHeight-m_minHeight)*0.5f;
pbox->center.x = m_PatchStart.x*m_phf->step.x + pbox->size.x;
pbox->center.y = m_PatchStart.y*m_phf->step.y + pbox->size.y;
pbox->center.z = m_minHeight + pbox->size.z;
pbox->Basis.SetIdentity();
pbox->bOriented = 0;
}
void CHeightfieldBV::GetNodeBV(BV *&pBV,int iNode)
{
pBV = &g_BVhf;
g_BVhf.hf = *m_phf;
g_BVhf.hf.Basis.SetIdentity();
g_BVhf.hf.bOriented = 0;
g_BVhf.hf.origin.zero();
}
void CHeightfieldBV::GetNodeBV(const matrix3x3f &Rw,const vectorf &offsw,float scalew, BV *&pBV, int iNode)
{
pBV = &g_BVhf;
g_BVhf.hf = *m_phf;
g_BVhf.hf.Basis = Rw.T();
g_BVhf.hf.bOriented = 1;
g_BVhf.hf.origin = offsw;
g_BVhf.hf.step = m_phf->step*scalew;
g_BVhf.hf.stepr = m_phf->stepr/scalew;
g_BVhf.hf.heightscale *= scalew;
}
void project_box_on_grid(box *pbox,grid *pgrid, geometry_under_test *pGTest, int &ix,int &iy,int &sx,int &sy,float &minz)
{
vectorf center; vectorf dim;
if (!pGTest) {
matrix3x3f Basis = pbox->Basis;
dim = pbox->size*Basis.Fabs();
center = pbox->center;
} else {
matrix3x3f Basis;
if (pbox->bOriented)
Basis = pbox->Basis*pGTest->R_rel;
else
Basis = pGTest->R_rel;
dim = (pbox->size*pGTest->rscale_rel)*Basis.Fabs();
center = ((pbox->center-pGTest->offset_rel)*pGTest->R_rel)*pGTest->rscale_rel;
}
ix = float2int((center.x-dim.x)*pgrid->stepr.x-0.5f); ix &= ~(ix>>31);
iy = float2int((center.y-dim.y)*pgrid->stepr.y-0.5f); iy &= ~(iy>>31);
sx = min(float2int((center.x+dim.x)*pgrid->stepr.x+0.5f),pgrid->size.x)-ix;
sy = min(float2int((center.y+dim.y)*pgrid->stepr.y+0.5f),pgrid->size.y)-iy;
minz = center.z-dim.z;
}
void CHeightfieldBV::MarkUsedTriangle(int itri, geometry_under_test *pGTest)
{
m_pUsedTriMap[itri>>5] |= 1u<<(itri&31);
}
int CHeightfieldBV::GetNodeContents(int iNode, BV *pBVCollider,int bColliderUsed,int bColliderLocal,
geometry_under_test *pGTest,geometry_under_test *pGTestOp)
{
int iStart,nCols,nRows,nPrims,ix,iy,ix0,iy0,i,j;
float minz;
if (pBVCollider->type==box::type) {
project_box_on_grid((box*)(primitive*)*pBVCollider,m_phf, (geometry_under_test*)((intptr_t)pGTest & -((intptr_t)bColliderLocal^1)),
ix0,iy0,nCols,nRows,minz);
ix = ix0-m_PatchStart.x; iy = iy0-m_PatchStart.y; ix &= ~(ix>>31); iy &= ~(iy>>31);
nCols = min(ix0+nCols,m_PatchStart.x+m_PatchSize.x)-ix-m_PatchStart.x; // don't forget to crop values to the current patch
nRows = min(iy0+nRows,m_PatchStart.y+m_PatchSize.y)-iy-m_PatchStart.y;
} else {
nCols=m_PatchSize.x; nRows=m_PatchSize.y; ix=iy=0;
}
//if (m_phf->gettype(ix,iy)==-1)
// return 0;
iStart = ix+iy*m_PatchSize.x;
if (!bColliderUsed) {
for(i=nPrims=0; i<nRows; i++,iStart+=m_PatchSize.x)
nPrims += m_pMesh->GetPrimitiveList(iStart*2,nCols*2, pBVCollider->type,*pBVCollider,bColliderLocal, pGTest,pGTestOp,
(primitive*)((char*)pGTest->primbuf+nPrims*pGTest->szprim), pGTest->idbuf+nPrims);
} else {
for(i=nPrims=0; i<nRows; i++,iStart+=m_PatchSize.x) for(j=0;j<nCols*2;j++) {
int itri = iStart*2+j;
if (!(m_pUsedTriMap[itri>>5]>>itri & 1))
nPrims += m_pMesh->GetPrimitiveList(itri,1, pBVCollider->type,*pBVCollider,bColliderLocal, pGTest,pGTestOp,
(primitive*)((char*)pGTest->primbuf+nPrims*pGTest->szprim), pGTest->idbuf+nPrims);
}
}
return nPrims;
}

View File

@@ -0,0 +1,36 @@
#ifndef heightfieldbv_h
#define heightfieldbv_h
#pragma once
class CHeightfieldBV : public CBVTree {
public:
CHeightfieldBV() { m_pUsedTriMap=0; }
virtual ~CHeightfieldBV() { if (m_pUsedTriMap) delete[] m_pUsedTriMap; }
virtual int GetType() { return BVT_HEIGHTFIELD; }
virtual float Build(CGeometry *pGeom);
void SetHeightfield(heightfield *phf);
virtual void GetBBox(box *pbox);
virtual int MaxPrimsInNode() { return m_PatchSize.x*m_PatchSize.y*2; }
virtual void GetNodeBV(BV *&pBV, int iNode=0);
virtual void GetNodeBV(BV *&pBV, const vectorf &sweepdir,float sweepstep, int iNode=0) {}
virtual void GetNodeBV(const matrix3x3f &Rw,const vectorf &offsw,float scalew, BV *&pBV, int iNode=0);
virtual void GetNodeBV(const matrix3x3f &Rw,const vectorf &offsw,float scalew, BV *&pBV, const vectorf &sweepdir,float sweepstep, int iNode=0) {}
virtual int GetNodeContents(int iNode, BV *pBVCollider,int bColliderUsed,int bColliderLocal,
geometry_under_test *pGTest,geometry_under_test *pGTestOp);
virtual void MarkUsedTriangle(int itri, geometry_under_test *pGTest);
CTriMesh *m_pMesh;
heightfield *m_phf;
vector2di m_PatchStart;
vector2di m_PatchSize;
float m_minHeight,m_maxHeight;
unsigned int *m_pUsedTriMap;
static BVheightfield g_BVhf;
};
void project_box_on_grid(box *pbox,grid *pgrid, geometry_under_test *pGTest, int &ix,int &iy,int &sx,int &sy,float &minz);
#endif

View File

@@ -0,0 +1,375 @@
#include "stdafx.h"
#include "utils.h"
#include "primitives.h"
#include "intersectionchecks.h"
#include "overlapchecks.h"
#include "unprojectionchecks.h"
#include "bvtree.h"
#include "geometry.h"
#include "trimesh.h"
#include "raybv.h"
#include "raygeom.h"
#include "heightfieldbv.h"
#include "heightfieldgeom.h"
CHeightfield* CHeightfield::CreateHeightfield(heightfield *phf)
{
m_hf = *phf;
m_hf.Basis.SetIdentity();
m_hf.origin.zero();
m_hf.stepr.x = 1.0f/phf->step.x; m_hf.stepr.y = 1.0f/phf->step.y;
int i = (phf->typemask^phf->typemask-1)+1>>1;
for(m_hf.typepower=0; !(i&1); i>>=1,m_hf.typepower++);
m_minHeight = 1E10f; m_maxHeight = -1E10f;
for(i=(phf->size.x+1)*(phf->size.y+1)-1; i>=0; i--) {
m_minHeight = min(m_minHeight, phf->getheight(i));
m_maxHeight = max(m_maxHeight, phf->getheight(i));
}
m_Tree.m_phf = &m_hf;
m_Tree.Build(this);
m_pTree = &m_Tree;
m_pVertices = new vectorf[m_nVerticesAlloc = 32];
m_pNormals = new vectorf[m_nTrisAlloc = 64];
m_pIndices = new index_t[m_nTrisAlloc*3];
m_pIds = new short[m_nTrisAlloc];
m_pTopology = new trinfo[m_nTrisAlloc];
m_Tree.m_pUsedTriMap = new unsigned int[(m_nTrisAlloc-1>>5)+1];
m_minVtxDist = (m_hf.step.x+m_hf.step.y)*1E-3f;
m_nVertices = m_nTris = 0;
m_flags = 3;
return this;
}
struct hf_cell_checker {
float dir2d_len,max_zcell,maxt;
int idcontact;
triangle hftri;
ray hfray;
heightfield *phf;
prim_inters inters;
vector2df org2d,dir2d;
int check_cell(const vector2di &icell, int &ilastcell) {
quotientf t((org2d+icell)*dir2d, dir2d_len*dir2d_len);
if (t.x>maxt || !phf->inrange(icell.x,icell.y))
return 1;
float h[4], zlowest = hfray.origin.z*t.y + hfray.dir.z*t.x - max_zcell;
int idcell = icell.x*phf->stride.x + icell.y*phf->stride.y, itype = phf->gettype(idcell);
h[0] = phf->getheight(idcell);
h[1] = phf->getheight(idcell+phf->stride.x);
h[2] = phf->getheight(idcell+phf->stride.y);
h[3] = phf->getheight(idcell+phf->stride.x+phf->stride.y);
if (zlowest<=max(max(max(h[0],h[1]),h[2]),h[3])*t.y && itype>=0) {
hftri.pt[0].x = hftri.pt[2].x = icell.x*phf->step.x; hftri.pt[1].x = hftri.pt[0].x+phf->step.x;
hftri.pt[0].y = hftri.pt[1].y = icell.y*phf->step.y; hftri.pt[2].y = hftri.pt[0].y+phf->step.y;
hftri.pt[0].z = h[0]; hftri.pt[1].z = h[1]; hftri.pt[2].z = h[2];
hftri.n = hftri.pt[1]-hftri.pt[0] ^ hftri.pt[2]-hftri.pt[0];
if (ray_tri_intersection(&hfray,&hftri, &inters) && hftri.n*hfray.dir<0)
{ idcontact = itype; return 1; }
hftri.pt[0] = hftri.pt[2]; hftri.pt[2].x += phf->step.x; hftri.pt[2].z = h[3];
hftri.n = hftri.pt[1]-hftri.pt[0] ^ hftri.pt[2]-hftri.pt[0];
if (ray_tri_intersection(&hfray,&hftri, &inters) && hftri.n*hfray.dir<0)
{ idcontact = itype; return 1; }
}
return 0;
}
};
int CHeightfield::Intersect(IGeometry *pCollider, geom_world_data *pdata1,geom_world_data *pdata2, intersection_params *pparams, geom_contact *&pcontacts)
{
if (pCollider->GetType()==GEOM_RAY) {
geometry_under_test GRay;
bool bKeepPrevContacts = pparams ? pparams->bKeepPrevContacts : false;
((CGeometry*)pCollider)->PrepareForIntersectionTest(&GRay, this,0, bKeepPrevContacts);
ray *pray = (ray*)GRay.primbuf;
float rscale;
hf_cell_checker hcc;
vectorf dirn = ((CRayGeom*)pCollider)->m_dirn, origin,dir;
unprojection_mode unproj;
contact contact_best;
hcc.phf = &m_hf;
if (!bKeepPrevContacts)
g_nTotContacts = 0;
// transform ray to grid coordinates
rscale = 1.0f/pdata1->scale;
hcc.hfray.origin = origin = ((pray->origin-pdata1->offset)*pdata1->R)*rscale;
hcc.hfray.dir = dir = (pray->dir*pdata1->R)*rscale;
hcc.inters.minPtDist2 = sqr(m_minVtxDist);
hcc.org2d.set(0.5f-hcc.hfray.origin.x*m_hf.stepr.x,0.5f-hcc.hfray.origin.y*m_hf.stepr.y);
hcc.dir2d.set(hcc.hfray.dir.x*m_hf.stepr.x,hcc.hfray.dir.y*m_hf.stepr.y);
hcc.dir2d_len = hcc.dir2d.len();
hcc.max_zcell = fabs_tpl(hcc.hfray.dir.z)*hcc.dir2d_len*(sqrt2*0.5f);
hcc.maxt = hcc.dir2d_len*(hcc.dir2d_len+sqrt2);
hcc.idcontact = -2;
if (DrawRayOnGrid(&m_hf, origin,dir, hcc) && hcc.idcontact!=-2) {
g_Contacts[g_nTotContacts].ptborder = &g_Contacts[g_nTotContacts].center;
g_Contacts[g_nTotContacts].center = (pdata1->R*hcc.inters.pt[0])*pdata1->scale + pdata1->offset;
g_Contacts[g_nTotContacts].nborderpt = 1;
g_Contacts[g_nTotContacts].parea = 0;
if (((CGeometry*)pCollider)->m_iCollPriority<m_iCollPriority || !pparams)
unproj.imode = -1;
else {
if (unproj.imode = pparams->iUnprojectionMode) {
if ((unproj.dir = pparams->axisOfRotation).len2()==0) {
unproj.dir = g_Contacts[g_nTotContacts].n^pray->dir;
//if (unproj.dir.len2()<0.002) unproj.dir = aray.dir.orthogonal();
if (unproj.dir.len2()<0.002) unproj.dir.SetOrthogonal(pray->dir);
unproj.dir.normalize();
}
unproj.center = pparams->centerOfRotation;
unproj.tmax = pi*0.5;
} else {
unproj.dir = pdata2->v-pdata1->v;
unproj.tmax = pparams->time_interval;
if (fabsf(unproj.dir.len2()-1.0f)>0.001f)
unproj.dir.normalize();
}
unproj.minPtDist = m_minVtxDist;
for(int i=0;i<3;i++) hcc.hftri.pt[i] = pdata1->R*hcc.hftri.pt[i]*pdata1->scale + pdata1->offset;
hcc.hftri.n = pdata1->R*hcc.hftri.n;
}
if (unproj.imode<0 || !g_Unprojector.Check(&unproj, triangle::type,ray::type, &hcc.hftri,-1,pray,-1, &contact_best)) {
g_Contacts[g_nTotContacts].t = ((pdata1->R*(hcc.inters.pt[0]-hcc.hfray.origin))*dirn)*pdata1->scale;
g_Contacts[g_nTotContacts].pt = g_Contacts[g_nTotContacts].center;
g_Contacts[g_nTotContacts].n = pdata1->R*hcc.inters.n.normalized();
g_Contacts[g_nTotContacts].dir.zero();
g_Contacts[g_nTotContacts].iUnprojMode = -1;
} else {
if (unproj.imode)
contact_best.t = atan2(contact_best.t,contact_best.taux);
g_Contacts[g_nTotContacts].t = contact_best.t;
g_Contacts[g_nTotContacts].pt = contact_best.pt;
g_Contacts[g_nTotContacts].n = contact_best.n;
g_Contacts[g_nTotContacts].dir = unproj.dir;
g_Contacts[g_nTotContacts].iUnprojMode = unproj.imode;
}
g_Contacts[g_nTotContacts].vel = 0;
g_Contacts[g_nTotContacts].id[0] = hcc.idcontact;
g_Contacts[g_nTotContacts].id[1] = -1;
pcontacts = g_Contacts+g_nTotContacts++;
if (pparams)
pparams->pGlobalContacts = g_Contacts;
return 1;
}
return 0;
}
return CTriMesh::Intersect(pCollider,pdata1,pdata2,pparams,pcontacts);
}
int CHeightfield::PrepareForIntersectionTest(geometry_under_test *pGTest, CGeometry *pCollider,geometry_under_test *pGTestColl, bool bKeepPrevContacts)
{
box abox,aboxext,*pbox; pCollider->GetBBox(&abox);
if (pGTestColl->sweepstep>0) {
ExtrudeBox(&abox, pGTestColl->sweepdir_loc,pGTestColl->sweepstep_loc, &aboxext);
pbox = &aboxext;
} else pbox = &abox;
int ix,iy,sx,sy,i,j,itri,icol,irow,icell;
float curx,cury,maxh,minz;
index_t *pIdx;
trinfo *pTop;
vectorf *pVtx;
project_box_on_grid(pbox,&m_hf, pGTest, ix,iy,sx,sy,minz);
for(i=ix,maxh=m_minHeight;i<=ix+sx;i++) for(j=iy;j<=iy+sy;j++)
maxh = max(maxh,m_hf.getheight(i,j));
if (minz>maxh || sx<=0 || sy<=0)
return 0;
m_Tree.m_PatchStart.set(ix,iy);
m_Tree.m_PatchSize.set(sx,sy);
m_nVertices = (sx+1)*(sy+1);
m_nTris = sx*sy*2;
m_nMaxVertexValency = 6;
if (m_nVerticesAlloc<m_nVertices) {
delete[] m_pVertices;
m_pVertices = new vectorf[m_nVerticesAlloc = (m_nVertices-1 & ~15)+16];
}
if (m_nTrisAlloc<m_nTris) {
delete[] m_pIndices; delete[] m_pNormals; delete[] m_pIds; delete[] m_pTopology; delete[] m_Tree.m_pUsedTriMap;
m_pNormals = new vectorf[m_nTrisAlloc = (m_nTris-1 & ~15)+16];
m_pIndices = new index_t[m_nTrisAlloc*3];
m_pIds = new short[m_nTrisAlloc];
m_pTopology = new trinfo[m_nTrisAlloc];
m_Tree.m_pUsedTriMap = new unsigned int[(m_nTrisAlloc-1>>5)+1];
}
m_Tree.m_minHeight = m_Tree.m_minHeight = m_hf.getheight(ix,iy);
for(j=0,pVtx=m_pVertices.data; j<=sy; j++) {
icell = ix*m_hf.stride.x + (iy+j)*m_hf.stride.y;
curx = m_hf.step.x*ix; cury = m_hf.step.y*(iy+j);
for(i=0; i<=sx; i++,pVtx++,icell+=m_hf.stride.x,curx+=m_hf.step.x) {
pVtx->Set(curx,cury,m_hf.getheight(icell));
m_Tree.m_minHeight = min(m_Tree.m_minHeight, pVtx->z);
m_Tree.m_maxHeight = max(m_Tree.m_maxHeight, pVtx->z);
}
}
for(irow=i=itri=0,pIdx=m_pIndices,pTop=m_pTopology; irow<sy; irow++,i++)
for(icol=0,icell=ix*m_hf.stride.x+(irow+iy)*m_hf.stride.y; icol<sx; icol++,itri+=2,i++,icell+=m_hf.stride.x) {
*pIdx++=i; *pIdx++=i+1; *pIdx++=i+sx+1;
m_pNormals[itri] = (m_pVertices[pIdx[1-3]]-m_pVertices[pIdx[0-3]] ^ m_pVertices[pIdx[2-3]]-m_pVertices[pIdx[0-3]]).normalized();
*pIdx++=i+sx+1; *pIdx++=i+1; *pIdx++=i+sx+2;
m_pNormals[itri+1] = (m_pVertices[pIdx[1-3]]-m_pVertices[pIdx[0-3]] ^ m_pVertices[pIdx[2-3]]-m_pVertices[pIdx[0-3]]).normalized();
pTop->ibuddy[0] = itri-sx*2+1 | irow-1>>31; pTop->ibuddy[1] = itri+1; pTop++->ibuddy[2] = itri-1 | icol-1>>31;
pTop->ibuddy[0] = itri; pTop->ibuddy[1] = itri+2 | sx-2-icol>>31; pTop++->ibuddy[2] = itri+sx*2 | sy-2-irow>>31;
m_pIds[itri] = m_pIds[itri+1] = m_hf.gettype(icell);
}
for(i=m_nTris-1>>5;i>=0;i--)
m_Tree.m_pUsedTriMap[i] = 0;
for(itri=0;itri<m_nTris;itri++) if (m_pIds[itri]==-1)
for(j=0;j<3;j++) if ((i=m_pTopology[itri].ibuddy[0])>=0) // remove connectivity for 'hole' triangles
m_pTopology[i].ibuddy[GetEdgeByBuddy(i,itri)] = -1;
return CTriMesh::PrepareForIntersectionTest(pGTest, pCollider,pGTestColl, bKeepPrevContacts);
}
inline void CheckPtEdgeDist(const vectorf *pte, const vectorf &pt, vectorf &ptres,int &iFeature)
{
vectorf edge = pte[1]-pte[0], dp = pt-pte[0];
float dp_edge = dp*edge, edge_len2 = edge.len2();
if ((dp^edge).len2()<(pt-ptres).len2()*edge_len2 && dp_edge>0 && (pt-pte[1])*edge<0) {
ptres = pte[0] + edge*(dp_edge/edge_len2);
iFeature = 0x20;
}
}
inline void CheckPtTriDist(const triangle &tri, const vectorf &pt, vectorf &ptres,int &iFeature)
{
float dist = (pt-tri.pt[0])*tri.n;
if (dist>0 && sqr(dist)<(pt-ptres).len2()*tri.n.len2() && (tri.pt[1]-tri.pt[0]^pt-tri.pt[0])*tri.n>0 &&
(tri.pt[2]-tri.pt[1]^pt-tri.pt[1])*tri.n>0 && (tri.pt[0]-tri.pt[2]^pt-tri.pt[2])*tri.n>0)
{
vectorf n = tri.n.normalized();
ptres = pt-n*(n*(pt-tri.pt[0]));
iFeature = 0x40;
}
}
int CHeightfield::FindClosestPoint(geom_world_data *pgwd, int &iPrim,int &iFeature, const vectorf &ptdst0,const vectorf &ptdst1,
vectorf *ptres, int nMaxIters)
{
triangle tri;
float h[4];
vectorf pt,ptres_loc;
int ix,iy,sx,sy,icell;
ptres[1] = ptdst0;
pt = ((ptdst0-pgwd->offset)*pgwd->R);
if (pgwd->scale!=1.0f) pt/=pgwd->scale;
ix = float2int(pt.x*m_hf.stepr.x-0.5f); iy = float2int(pt.y*m_hf.stepr.y-0.5f);
icell = ix*m_hf.stride.x + iy*m_hf.stride.y;
if ((unsigned int)ix>(unsigned int)m_hf.size.x-2 || (unsigned int)iy>(unsigned int)m_hf.size.y-2 || m_hf.gettype(icell)<0) {
ptres[0].Set(1E10,1E10,1E10); return -1;
}
h[0] = m_hf.getheight(icell);
h[1] = m_hf.getheight(icell+m_hf.stride.x);
h[2] = m_hf.getheight(icell+m_hf.stride.y);
h[3] = m_hf.getheight(icell+m_hf.stride.x+m_hf.stride.y);
sx = isneg(m_hf.step.x*ix+0.5f-pt.x);
sy = isneg(m_hf.step.y*iy+0.5f-pt.y);
ptres_loc.Set((ix+sx)*m_hf.step.x, (iy+sy)*m_hf.step.y, h[sx+sy*2]);
iFeature = 0;
tri.pt[0].x = tri.pt[2].x = ix*m_hf.step.x; tri.pt[1].x = tri.pt[0].x+m_hf.step.x;
tri.pt[0].y = tri.pt[1].y = iy*m_hf.step.y; tri.pt[2].y = tri.pt[0].y+m_hf.step.y;
tri.pt[0].z = h[0]; tri.pt[1].z = h[1]; tri.pt[2].z = h[2];
tri.n = tri.pt[1]-tri.pt[0] ^ tri.pt[2]-tri.pt[0];
CheckPtTriDist(tri,pt, ptres_loc,iFeature);
tri.pt[0] = tri.pt[2]; tri.pt[2].x += m_hf.step.x; tri.pt[2].z = h[3];
tri.n = tri.pt[1]-tri.pt[0] ^ tri.pt[2]-tri.pt[0];
CheckPtTriDist(tri,pt, ptres_loc,iFeature);
tri.pt[1].x = tri.pt[0].x = (ix+sx)*m_hf.step.x;
tri.pt[1].y = (tri.pt[0].y = iy*m_hf.step.y) + m_hf.step.y;
tri.pt[0].z = h[sx]; tri.pt[1].z = h[sx+2];
CheckPtEdgeDist(tri.pt, pt, ptres_loc,iFeature);
tri.pt[1].y = tri.pt[0].y = (iy+sy)*m_hf.step.y;
tri.pt[1].x = (tri.pt[0].x = ix*m_hf.step.x) + m_hf.step.x;
tri.pt[0].z = h[sy*2]; tri.pt[1].z = h[sy*2+1];
CheckPtEdgeDist(tri.pt, pt, ptres_loc,iFeature);
tri.pt[0].Set((ix+1)*m_hf.step.x, iy*m_hf.step.y, h[1]);
tri.pt[1].Set(ix*m_hf.step.x, (iy+1)*m_hf.step.y, h[2]);
CheckPtEdgeDist(tri.pt, pt, ptres_loc,iFeature);
iPrim = 0;
ptres[0] = pgwd->R*ptres_loc*pgwd->scale + pgwd->offset;
return 1;
}
void CHeightfield::CalcVolumetricPressure(geom_world_data *gwd, const vectorf &epicenter,float k,float rmin,
const vectorf &centerOfMass, vectorf &P,vectorf &L)
{
return;
}
int CHeightfield::DrawToOcclusionCubemap(const geom_world_data *pgwd, int iStartPrim,int nPrims, int iPass, int *pGrid[6],int nRes,
float rmin,float rmax,float zscale)
{
int nTris,ix,iy,idcell;
float rscale = pgwd->scale==1.0f ? 1.0f:1.0f/pgwd->scale, h[4];
vector2di irect[2];
triangle tri;
sphere sph;
sph.center = (-pgwd->offset*rscale)*pgwd->R;
sph.r = rmax*rscale;
irect[0].x = max(0,min(m_hf.size.x, float2int((sph.center.x-sph.r)*m_hf.stepr.x-0.5f)));
irect[0].y = max(0,min(m_hf.size.y, float2int((sph.center.y-sph.r)*m_hf.stepr.y-0.5f)));
irect[1].x = max(0,min(m_hf.size.x, float2int((sph.center.x+sph.r)*m_hf.stepr.x+0.5f)));
irect[1].y = max(0,min(m_hf.size.y, float2int((sph.center.y+sph.r)*m_hf.stepr.y+0.5f)));
sph.center.zero();
sph.r = rmax;
for(ix=irect[0].x,nTris=0;ix<irect[1].x;ix++) for(iy=irect[0].y;iy<irect[1].y;iy++) {
idcell = ix*m_hf.stride.x + iy*m_hf.stride.y;
if (m_hf.gettype(idcell)>=0) {
h[0] = m_hf.getheight(idcell);
h[1] = m_hf.getheight(idcell+m_hf.stride.x);
h[2] = m_hf.getheight(idcell+m_hf.stride.y);
h[3] = m_hf.getheight(idcell+m_hf.stride.x+m_hf.stride.y);
tri.pt[0].x = tri.pt[2].x = ix*m_hf.step.x; tri.pt[1].x = tri.pt[0].x+m_hf.step.x;
tri.pt[0].y = tri.pt[1].y = iy*m_hf.step.y; tri.pt[2].y = tri.pt[0].y+m_hf.step.y;
tri.pt[0].z = h[0]; tri.pt[1].z = h[1]; tri.pt[2].z = h[2];
tri.pt[0] = pgwd->R*tri.pt[0]*pgwd->scale+pgwd->offset;
tri.pt[1] = pgwd->R*tri.pt[1]*pgwd->scale+pgwd->offset;
tri.pt[2] = pgwd->R*tri.pt[2]*pgwd->scale+pgwd->offset;
tri.n = tri.pt[1]-tri.pt[0] ^ tri.pt[2]-tri.pt[0];
if (tri_sphere_overlap_check(&tri,&sph)) {
RasterizePolygonIntoCubemap(tri.pt,3, iPass, pGrid,nRes, rmin,rmax,zscale);
nTris++;
}
tri.pt[0] = tri.pt[2]; tri.pt[2] += pgwd->R*vectorf(pgwd->scale*m_hf.step.x,0,0);
tri.pt[2] += pgwd->R*vectorf(0,0,pgwd->scale*(h[3]-h[2]));
tri.n = tri.pt[1]-tri.pt[0] ^ tri.pt[2]-tri.pt[0];
if (tri_sphere_overlap_check(&tri,&sph)) {
RasterizePolygonIntoCubemap(tri.pt,3, iPass, pGrid,nRes, rmin,rmax,zscale);
nTris++;
}
}
}
return nTris;
}
void CHeightfield::GetMemoryStatistics(ICrySizer *pSizer)
{
CTriMesh::GetMemoryStatistics(pSizer);
pSizer->AddObject(this, sizeof(CHeightfield));
}

View File

@@ -0,0 +1,34 @@
#ifndef heightfieldgeom_h
#define heightfieldgeom_h
#pragma once
class CHeightfield : public CTriMesh {
public:
CHeightfield() {}
virtual ~CHeightfield() { m_pTree=0; }
CHeightfield* CreateHeightfield(heightfield *phf);
virtual int GetType() { return GEOM_HEIGHTFIELD; }
virtual int Intersect(IGeometry *pCollider, geom_world_data *pdata1,geom_world_data *pdata2, intersection_params *pparams, geom_contact *&pcontacts);
virtual int PrepareForIntersectionTest(geometry_under_test *pGTest, CGeometry *pCollider,geometry_under_test *pGTestColl, bool bKeepPrevContacts=false);
virtual int PointInsideStatus(const vectorf &pt) { return -1; }
virtual int FindClosestPoint(geom_world_data *pgwd, int &iPrim,int &iFeature, const vectorf &ptdst0,const vectorf &ptdst1,
vectorf *ptres, int nMaxIters=10);
virtual void CalcVolumetricPressure(geom_world_data *gwd, const vectorf &epicenter,float k,float rmin,
const vectorf &centerOfMass, vectorf &P,vectorf &L);
virtual int IsConvex(float tolerance) { return 0; }
virtual int DrawToOcclusionCubemap(const geom_world_data *pgwd, int iStartPrim,int nPrims, int iPass, int *pGrid[6],int nRes,
float rmin,float rmax,float zscale);
virtual void PrepareForRayTest(float raylen) {}
virtual CBVTree *GetBVTree() { return &m_Tree; }
virtual int GetPrimitive(int iPrim, primitive *pprim) { *(heightfield*)pprim = m_hf; return sizeof(heightfield); }
virtual void GetMemoryStatistics(ICrySizer *pSizer);
heightfield m_hf;
CHeightfieldBV m_Tree;
float m_minHeight,m_maxHeight;
int m_nVerticesAlloc,m_nTrisAlloc;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,55 @@
#ifndef intersectionchecks_h
#define intersectionchecks_h
typedef int (*intersection_check)(const primitive*,const primitive*,prim_inters*);
int default_intersection(const primitive*,const primitive*, prim_inters *pinters);
int tri_tri_intersection(const triangle *ptri1, const triangle *ptri2, prim_inters *pinters);
int tri_box_intersection(const triangle *ptri, const box *pbox, prim_inters *pinters);
int box_tri_intersection(const box *pbox, const triangle *ptri, prim_inters *pinters);
int tri_cylinder_intersection(const triangle *ptri, const cylinder *pcyl, prim_inters *pinters);
int cylinder_tri_intersection(const cylinder *pcyl, const triangle *ptri, prim_inters *pinters);
int tri_sphere_intersection(const triangle *ptri, const sphere *psphere, prim_inters *pinters);
int sphere_tri_intersection(const sphere *psphere, const triangle *ptri, prim_inters *pinters);
int tri_ray_intersection(const triangle *ptri, const ray *pray, prim_inters *pinters);
int ray_tri_intersection(const ray *pray, const triangle *ptri, prim_inters *pinters);
int tri_plane_intersection(const triangle *ptri, const plane *pplane, prim_inters *pinters);
int plane_tri_intersection(const plane *pplane, const triangle *ptri, prim_inters *pinters);
int box_box_intersection(const box *pbox1, const box *pbox2, prim_inters *pinters);
int box_cylinder_intersection(const box *pbox, const cylinder *pcyl, prim_inters *pinters);
int cylinder_box_intersection(const cylinder *pcyl, const box *pbox, prim_inters *pinters);
int box_sphere_intersection(const box *pbox, const sphere *psphere, prim_inters *pinters);
int sphere_box_intersection(const sphere *psphere, const box *pbox, prim_inters *pinters);
int box_ray_intersection(const box *pbox, const ray *pray, prim_inters *pinters);
int ray_box_intersection(const ray *pray, const box *pbox, prim_inters *pinters);
int box_plane_intersection(const box *pbox, const plane *pplane, prim_inters *pinters);
int plane_box_intersection(const plane *pplane, const box *pbox, prim_inters *pinters);
int cylinder_cylinder_intersection(const cylinder *pcyl1, const cylinder *pcyl2, prim_inters *pinters);
int cylinder_sphere_intersection(const cylinder *pcyl, const sphere *psphere, prim_inters *pinters);
int sphere_cylinder_intersection(const sphere *psphere, const cylinder *pcyl, prim_inters *pinters);
int cylinder_ray_intersection(const cylinder *pcyl, const ray *pray, prim_inters *pinters);
int ray_cylinder_intersection(const ray *pray, const cylinder *pcyl, prim_inters *pinters);
int cylinder_plane_intersection(const cylinder *pcyl, const plane *pplane, prim_inters *pinters);
int plane_cylinder_intersection(const plane *pplane, const cylinder *pcyl, prim_inters *pinters);
int sphere_sphere_intersection(const sphere *psphere1, const sphere *psphere2, prim_inters *pinters);
int sphere_ray_intersection(const sphere *psphere, const ray *pray, prim_inters *pinters);
int ray_sphere_intersection(const ray *pray, const sphere *psphere, prim_inters *pinters);
int sphere_plane_intersection(const sphere *psphere, const plane *pplane, prim_inters *pinters);
int plane_sphere_intersection(const plane *pplane, const sphere *psphere, prim_inters *pinters);
int ray_plane_intersection(const ray *pray, const plane *pplane, prim_inters *pinters);
int plane_ray_intersection(const plane *pplane, const ray *pray, prim_inters *pinters);
class CIntersectionChecker {
public:
CIntersectionChecker();
int Check(int type1,int type2, const primitive* prim1,const primitive *prim2, prim_inters* pinters) {
return table[type1][type2](prim1,prim2, pinters);
}
int CheckExists(int type1,int type2) {
return table[type1][type2]!=default_intersection;
}
intersection_check table[NPRIMS][NPRIMS];
};
extern CIntersectionChecker g_Intersector;
#endif

File diff suppressed because it is too large Load Diff

1731
CryPhysics/livingentity.cpp Normal file

File diff suppressed because it is too large Load Diff

146
CryPhysics/livingentity.h Normal file
View File

@@ -0,0 +1,146 @@
//////////////////////////////////////////////////////////////////////
//
// Living Entity header
//
// File: livingentity.h
// Description : CLivingEntity class header
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#ifndef livingentity_h
#define livingentity_h
#pragma once
const int SZ_ACTIONS = 128;
const int SZ_HISTORY = 128;
struct le_history_item {
vectorf pos;
quaternionf q;
vectorf v;
int bFlying;
vectorf nslope;
float timeFlying;
float minFlyTime;
float timeUseLowCap;
int idCollider;
int iColliderPart;
vectorf posColl;
float dt;
};
struct le_contact {
CPhysicalEntity *pent;
int ipart;
vectorf pt,ptloc;
vectorf n;
float penetration;
vectorf center;
};
class CLivingEntity : public CPhysicalEntity {
public:
CLivingEntity(CPhysicalWorld *pWorld);
virtual ~CLivingEntity();
virtual pe_type GetType() { return PE_LIVING; }
virtual int SetParams(pe_params*);
virtual int GetParams(pe_params*);
virtual int GetStatus(pe_status*);
virtual int Action(pe_action*);
virtual void StartStep(float time_interval);
virtual float GetMaxTimeStep(float time_interval);
virtual int Step(float time_interval);
void StepBackEx(float time_interval,bool bRollbackHistory=true);
virtual void StepBack(float time_interval) { StepBackEx(time_interval); }
virtual float CalcEnergy(float time_interval);
virtual int RegisterContacts(float time_interval,int nMaxPlaneContacts);
virtual int Update(float time_interval, float damping);
virtual int Awake(int bAwake=1,int iSource=0);
virtual void AlertNeighbourhoodND() { ReleaseGroundCollider(); CPhysicalEntity::AlertNeighbourhoodND(); }
virtual void ComputeBBox() {
CPhysicalEntity::ComputeBBox(); m_BBox[0].z = min(m_BBox[0].z,m_pos.z-m_hPivot);
m_BBox[1].z = max(m_BBox[1].z,m_pos.z-m_hPivot+(m_hHead+m_HeadGeom.m_sphere.r)*isneg(0.001f-m_HeadGeom.m_sphere.r));
}
virtual int AddGeometry(phys_geometry *pgeom, pe_geomparams* params,int id=-1);
virtual void RemoveGeometry(int id);
virtual void DrawHelperInformation(void (*DrawLineFunc)(float*,float*), int flags);
enum snapver { SNAPSHOT_VERSION = 2 };
virtual int GetStateSnapshot(class CStream &stm, float time_back=0, int flags=0);
virtual int SetStateFromSnapshot(class CStream &stm, int flags=0);
virtual void GetMemoryStatistics(ICrySizer *pSizer);
virtual float GetMassInv() { return m_massinv; }
virtual void GetContactMatrix(const vectorf &pt, int ipart, matrix3x3f &K) {
K(0,0)+=m_massinv; K(1,1)+=m_massinv; K(2,2)+=m_massinv;
}
virtual void GetSpatialContactMatrix(const vectorf &pt, int ipart, float Ibuf[][6]) {
Ibuf[3][0]+=m_massinv; Ibuf[4][1]+=m_massinv; Ibuf[5][2]+=m_massinv;
}
float ShootRayDown(CPhysicalEntity **pentlist,int nents, const vectorf &pos,vectorf &nslope, float time_interval=0,
bool bUseRotation=false,bool bUpdateGroundCollider=false,bool bIgnoreSmallObjects=true);
void AddLegsImpulse(const vectorf &vel, const vectorf &nslope, bool bInstantChange);
void ReleaseGroundCollider();
void SetGroundCollider(CPhysicalEntity *pCollider);
void SyncWithGroundCollider(float time_interval);
void RegisterContact(const vectorf& pt,const vectorf& n, CPhysicalEntity *pCollider, int ipart,int idmat);
void RegisterUnprojContact(const le_contact &unproj);
int IsPositionFree(const vectorf *BBox,float newh,const vectorf &newdim);
void AllocateExtendedHistory();
vectorf m_vel,m_velRequested,m_gravity,m_nslope;
float m_kInertia,m_kAirControl,m_kAirResistance, m_hCyl,m_hEye,m_hPivot,m_hHead;
vectorf m_size;
float m_dh,m_dhSpeed,m_dhAcc,m_stablehTime,m_hLatest,m_nodSpeed;
float m_mass,m_massinv;
int m_bFlying,m_bJumpRequested,m_bSwimming, m_surface_idx, m_lastGroundSurfaceIdx;
float m_timeFlying,m_minFlyTime,m_timeForceInertia;
float m_slopeSlide,m_slopeClimb,m_slopeJump,m_slopeFall;
float m_maxVelGround;
CCylinderGeom m_CylinderGeom;
CSphereGeom m_SphereGeom,m_HeadGeom;
phys_geometry m_CylinderGeomPhys;
int m_bIgnoreCommands;
int m_bStateReading;
int m_bActive;
float m_timeUseLowCap;
float m_timeSinceStanceChange;
float m_timeSinceImpulseContact;
int m_bActiveEnvironment;
int m_bStuck;
float m_dhHist[2],m_timeOnStairs;
float m_timeStepFull,m_timeStepPerformed;
int m_iSnapshot;
int m_iTimeLastSend;
CPhysicalEntity *m_pLastGroundCollider;
int m_iLastGroundColliderPart;
vectorf m_posLastGroundColl;
vectorf m_velGround;
vectorf m_deltaPos,m_posLocal;
float m_timeSmooth;
int m_bUseSphere;
le_history_item *m_history,m_history_buf[4];
int m_szHistory,m_iHist;
pe_action_move *m_actions,m_actions_buf[16];
int m_szActions,m_iAction;
coll_history_item m_collision;
le_contact *m_pContacts;
int m_nContacts,m_nContactsAlloc;
int m_nSensors;
vectorf *m_pSensors,*m_pSensorsPoints,*m_pSensorsSlopes;
int m_iSensorsActive;
};
#endif

764
CryPhysics/matrixnm.cpp Normal file
View File

@@ -0,0 +1,764 @@
//////////////////////////////////////////////////////////////////////
//
// NxM Matrix
//
// File: matrixnm.cpp
// Description : matrixnm template class implementation for float and real
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "utils.h"
#ifdef USE_MATRIX_POOLS
DECLARE_MTXNxM_POOL(float,512)
DECLARE_VECTORN_POOL(float,256)
#ifndef REAL_IS_FLOAT
DECLARE_MTXNxM_POOL(real,512)
DECLARE_VECTORN_POOL(real,256)
#endif
#endif
int g_bHasSSE;
inline float getlothresh(float) { return 1E-10f; }
inline float gethithresh(float) { return 1E10f; }
inline double getlothresh(double) { return 1E-20; }
inline double gethithresh(double) { return 1E20; }
template<class ftype>
int matrix_tpl<ftype>::jacobi_transformation(matrix_tpl<ftype> &evec, ftype *eval, ftype prec) const
{
if (!(flags & mtx_symmetric) || nCols!=nRows) return 0;
matrix_tpl a(*this);
int n = nRows, p,q,r,iter,pmax,qmax,sz=nRows*nCols;
ftype theta,t,s,c,apr,aqr,arp,arq,thresh=prec,amax;
evec.identity();
evec.flags = (evec.flags & mtx_foreign_data) | mtx_orthogonal | mtx_normal;
for(iter=0; iter<nRows*nCols*10; iter++) {
for(p=0,amax=thresh,pmax=-1;p<n-1;p++) for(q=p+1;q<n;q++) if (sqr(a[p][q])>amax)
{ amax=sqr(a[p][q]); pmax=p; qmax=q; }
if (pmax==-1)
goto exitjacobi;
p=pmax; q=qmax;
theta = (ftype)0.5*(a[q][q]-a[p][p])/a[p][q];
if (fabs_tpl(theta)<gethithresh(theta)) {
t = sqrt_tpl(theta*theta+1);
if (theta>0) t = -theta-t;
else t -= theta;
c = 1/sqrt_tpl(1+t*t); s = t*c;
for(r=0;r<n;r++) { arp=a[r][p];arq=a[r][q]; a[r][p]=c*arp-s*arq; a[r][q]=c*arq+s*arp; }
for(r=0;r<n;r++) { apr=a[p][r];aqr=a[q][r]; a[p][r]=c*apr-s*aqr; a[q][r]=c*aqr+s*apr; }
for(r=0;r<n;r++) { apr=evec[p][r];aqr=evec[q][r]; evec[p][r]=c*apr-s*aqr; evec[q][r]=c*aqr+s*apr; }
}
a[p][q] = 0;
if (iter==sz+1) thresh += getlothresh(thresh);
}
iter=0;
exitjacobi:
for(p=0;p<n*n;p++) {
t = fabs_tpl(evec.data[p]);
if (t<(ftype)1E-6) evec.data[p]=0;
else if (fabs_tpl(t-1)<getlothresh(t))
evec.data[p]=sgnnz(evec.data[p]);
}
for(p=0;p<n;p++) eval[p] = a[p][p];
return iter; // not converged during iterations limit
}
template<class ftype>
int matrix_tpl<ftype>::conjugate_gradient(ftype *startx,ftype *rightside, ftype minlen,ftype minel) const
{
ftype a,b,r2,r2new,denom,maxel;
int i,iter=nRows*3;
minlen*=minlen;
ftype buf[24],*pbuf = nRows>8 ? new ftype[nRows*3]:buf;
vectorn_tpl<ftype> x(nRows,startx),rh(nRows,rightside),r(nRows,pbuf),p(nRows,pbuf+nRows),Ap(nRows,pbuf+nRows*2);
(r=rh)-=*this*x; p=r;
r2=r.len2();
do {
Ap = *this*p; denom = p*Ap;
if (sqr(denom)<1E-30) break;
a = r2/denom;
#if defined(LINUX)
r = ::operator-=(r, (const vectorn_tpl<ftype>&)(Ap*a));
#else
r -= Ap*a;
#endif
r2new=r.len2();
if (r2new>r2*500)
break;
#if defined(LINUX)
x = ::operator+=(x, (const vectorn_tpl<ftype>&)(p*a));
#else
x += p*a;
#endif
b = r2new/r2; r2=r2new;
(p*=b)+=r;
for(i=0,maxel=0;i<nRows;i++) maxel = max(maxel,fabs_tpl(r[i]));
} while (--iter && (r2new>minlen || maxel>minel));
if (pbuf!=buf) delete pbuf;
return nRows-iter;
}
template<class ftype>
int matrix_tpl<ftype>::biconjugate_gradient(ftype *startx,ftype *rightside, ftype minlen,ftype minel) const
{
ftype a,b,r2,r2new,err,denom,maxel;
int i,iter=nRows*3;
minlen*=minlen;
ftype buf[40],*pbuf = nRows>8 ? new ftype[nRows*5]:buf;
vectorn_tpl<ftype> x(nRows,startx),rh(nRows,rightside),r(nRows,pbuf),rc(nRows,pbuf+nRows),p(nRows,pbuf+nRows*2),
pc(nRows,pbuf+nRows*3),Ap(nRows,pbuf+nRows*4);
(r=rh)-=*this*x; rc=r; p=r; pc=rc; r2 = r.len2();
do {
Ap = *this*p; denom = pc*Ap;
if (sqr(denom)<1E-30) break;
a = r2/denom;
#if defined(LINUX)
r = ::operator-=(r, (const vectorn_tpl<ftype>&)(Ap*a));
rc = ::operator-=(rc, (const vectorn_tpl<ftype>&)((pc**this)*a));
x = ::operator+=(x, (const vectorn_tpl<ftype>&)(p*a));
#else
r -= Ap*a;
rc -= (pc**this)*a;
x += p*a;
#endif
r2new = rc*r;
b = r2new/r2; r2 = r2new;
(p*=b)+=r; (pc*=b)+=rc;
for(err=maxel=0,i=0;i<nRows;i++) {
err += sqr(r.data[i]);
maxel = max(maxel,fabs_tpl(r[i]));
}
} while(--iter && (err>minlen || maxel>minel) && sqr(r2)>1E-30);
if (pbuf!=buf) delete pbuf;
return nRows-iter;
}
template<class ftype>
int matrix_tpl<ftype>::minimum_residual(ftype *startx,ftype *rightside, ftype minlen,ftype minel) const
{
ftype a,b,r2,r2new,err,denom,maxel;
int i,iter=nRows*3;
minlen*=minlen;
ftype buf[40],*pbuf = nRows>8 ? new ftype[nRows*5]:buf;
vectorn_tpl<ftype> x(nRows,startx),rh(nRows,rightside),r(nRows,pbuf),rc(nRows,pbuf+nRows),p(nRows,pbuf+nRows*2),
Ap(nRows,pbuf+nRows*4);
(r=rh)-=*this*x;
rc=*this*r;
p=r;
r2 = rc*r;
do {
Ap = *this*p; denom = Ap.len2();
if (sqr(denom)<1E-30) break;
a = r2/denom;
#if defined(LINUX)
r = ::operator-=(r, (const vectorn_tpl<ftype>&)(Ap*a));
#else
r -= Ap*a;
#endif
rc = *this*r;
#if defined(LINUX)
x = ::operator+=(x, (const vectorn_tpl<ftype>&)(p*a));
#else
x += p*a;
#endif
r2new = rc*r;
b = r2new/r2; r2 = r2new;
(p*=b)+=r;
for(err=maxel=0,i=0;i<nRows;i++) {
err += sqr(r.data[i]);
maxel = max(maxel,fabs_tpl(r[i]));
}
} while(--iter && (err>minlen || maxel>minel) && sqr(r2)>1E-30);
if (pbuf!=buf) delete pbuf;
return nRows-iter;
}
template<class ftype>
int matrix_tpl<ftype>::LUdecomposition(ftype *&LUdata,int *&LUidx) const
{
if (nRows!=nCols) return 0;
int i,j,k,imax,alloc=(LUdata==0 | (LUidx==0)<<1);
ftype aij,bij,maxaij,t;
if (alloc & 1) LUdata = new ftype[nRows*nRows];
if (alloc & 2) LUidx = new int[nRows];
matrix_tpl<ftype> LU(nRows,nRows,0,LUdata);
LU = *this;
for(j=0;j<nRows;j++) {
for(i=0;i<=j;i++) {
for(k=0,bij=LU[i][j]; k<i; k++) bij -= LU[i][k]*LU[k][j];
LU[i][j] = bij;
}
for(maxaij=0,imax=j ;i<nRows;i++) {
for(k=0,aij=LU[i][j]; k<j; k++) aij -= LU[i][k]*LU[k][j];
LU[i][j] = aij;
if (aij*aij > maxaij*maxaij)
{ maxaij=aij; imax=i; }
}
LUidx[j] = imax;
if (j==nRows-1 && LU[j][j]!=0) break; // no aij in this case
if (maxaij==0) { // the matrix is singular
if (alloc & 1) delete[] LUdata;
if (alloc & 2) delete[] LUidx;
return 0;
}
if (imax!=j) for(k=0;k<nRows;k++)
{ t=LU[imax][k]; LU[imax][k]=LU[j][k]; LU[j][k]=t; }
maxaij = (ftype)1.0/maxaij;
for(i=j+1;i<nRows;i++)
LU[i][j] *= maxaij;
}
return 1;
}
template<class ftype>
int matrix_tpl<ftype>::solveAx_b(ftype *x,ftype *b, ftype *LUdata,int *LUidx) const
{
int LUidx_buf[16],alloc=0;
if (!LUdata) {
if (nRows*nRows*2<sizeof(mtx_pool)/sizeof(mtx_pool[0])) {
if (mtx_pool_pos+nRows*nRows > sizeof(mtx_pool)/sizeof(mtx_pool[0]))
mtx_pool_pos = 0;
LUdata = mtx_pool+mtx_pool_pos; mtx_pool_pos += nRows*nRows;
}
if (nRows<=sizeof(LUidx_buf)/sizeof(LUidx_buf[0])) LUidx = LUidx_buf;
alloc = LUdata==0 | (LUidx==0)<<1;
if (!LUdecomposition(LUdata,LUidx)) return 0;
}
int i,j; ftype xi;
matrix_tpl<ftype> LU(nRows,nRows,0,LUdata);
for(i=0;i<nRows;i++) x[i]=b[i];
for(i=0;i<nRows;i++) {
xi=x[i]; x[i]=x[LUidx[i]]; x[LUidx[i]]=xi;
for(j=0;j<i;j++) x[i]-=LU[i][j]*x[j];
}
for(i=nRows-1;i>=0;i--) {
for(j=i+1;j<nRows;j++) x[i]-=LU[i][j]*x[j];
x[i] /= LU[i][i];
}
if (alloc & 1) delete[] LUdata;
if (alloc & 2) delete[] LUidx;
return 1;
}
template<class ftype>
matrix_tpl<ftype>& matrix_tpl<ftype>::invert()
{
if (flags & mtx_orthogonal)
return transpose();
if (nRows!=nCols)
return *this;
int i,j; ftype det=0;
if (nRows==1)
data[0]=(ftype)1.0/data[0];
else if (nRows==2) {
det = data[0]*data[3]-data[1]*data[2];
if (det==0) return *this; det = (ftype)1.0/det;
ftype oldata[4]; for(i=0;i<4;i++) oldata[i]=data[i];
data[0]=oldata[3]*det; data[1]=-oldata[1]*det;
data[2]=-oldata[2]*det; data[3]=oldata[0]*det;
} else if (nRows==3) {
for(i=0;i<3;i++) det+=data[i]*data[inc_mod3[i]+3]*data[dec_mod3[i]+6];
for(i=0;i<3;i++) det-=data[dec_mod3[i]]*data[inc_mod3[i]+3]*data[i+6];
if (det==0) return *this; det = (ftype)1.0/det;
ftype oldata[9]; for(i=0;i<9;i++) oldata[i]=data[i];
for(i=0;i<3;i++) for(j=0;j<3;j++)
data[i+j*3] = (oldata[dec_mod3[i]*3+dec_mod3[j]]*oldata[inc_mod3[i]*3+inc_mod3[j]]-
oldata[dec_mod3[i]*3+inc_mod3[j]]*oldata[inc_mod3[i]*3+dec_mod3[j]])*det;
} else {
ftype *LUdata=0,*colmark; int *LUidx=0,LUidx_buf[32], alloc=0;
if (nRows*nRows*2<sizeof(mtx_pool)/sizeof(mtx_pool[0])) {
if (mtx_pool_pos+nRows*nRows > sizeof(mtx_pool)/sizeof(mtx_pool[0]))
mtx_pool_pos = 0;
LUdata = mtx_pool+mtx_pool_pos; mtx_pool_pos += nRows*nRows;
} else alloc = 1;
if (nRows<=sizeof(LUidx_buf)/sizeof(LUidx_buf[0])) LUidx = LUidx_buf;
else alloc |= 2;
if (!LUdecomposition(LUdata,LUidx)) return *this;
if (nRows*2<sizeof(mtx_pool)/sizeof(mtx_pool[0])) {
if (mtx_pool_pos+nRows > sizeof(mtx_pool)/sizeof(mtx_pool[0]))
mtx_pool_pos=0;
colmark=mtx_pool+mtx_pool_pos; mtx_pool_pos+=nRows;
} else {
colmark = new ftype[nRows]; alloc |= 4;
}
for(i=0;i<nRows;i++) colmark[i]=0;
for(i=0;i<nRows;i++) {
colmark[i]=1; solveAx_b(data+i*nRows,colmark, LUdata,LUidx); colmark[i]=0;
}
transpose();
if (alloc & 1) delete[] LUdata;
if (alloc & 2) delete[] LUidx;
if (alloc & 4) delete[] colmark;
}
flags = flags & (mtx_normal | mtx_orthogonal | mtx_symmetric | mtx_PD | mtx_PSD | mtx_diagonal | mtx_identity | mtx_foreign_data);
return *this;
}
template<class ftype>
ftype matrix_tpl<ftype>::determinant(ftype *LUdata,int *LUidx) const
{
if (nRows!=nCols) return 0;
int i,j; ftype det=0;
if (nRows==1)
det = data[0];
else if (nRows==2)
det = data[0]*data[3]-data[1]*data[2];
else if (nRows==3) {
for(i=0;i<3;i++) det+=data[i]*data[inc_mod3[i]+3]*data[dec_mod3[i]+6];
for(i=0;i<3;i++) det-=data[dec_mod3[i]]*data[inc_mod3[i]+3]*data[i+6];
} else if (LUdecomposition(LUdata,LUidx)) {
ftype *LUdata=0; int *LUidx=0,LUidx_buf[32], alloc=0;
if (nRows*nRows*2<sizeof(mtx_pool)/sizeof(mtx_pool[0])) {
if (mtx_pool_pos+nRows*nRows > sizeof(mtx_pool)/sizeof(mtx_pool[0]))
mtx_pool_pos = 0;
LUdata = mtx_pool+mtx_pool_pos; mtx_pool_pos += nRows*nRows;
} else alloc = 1;
if (nRows<=sizeof(LUidx_buf)/sizeof(LUidx_buf[0])) LUidx = LUidx_buf;
else alloc |= 2;
if (!LUdecomposition(LUdata,LUidx)) return 0;
for(i=j=0,det=1;i<nRows;i++,j+=nRows+1) det*=LUdata[j];
for(i=j=0;i<nRows;i++) j+=LUidx[i]!=i;
if (j&2) det*=-1;
if (alloc & 1) delete[] LUdata;
if (alloc & 2) delete[] LUidx;
}
return det;
}
// Linear programming with simplex method
template<class ftype>
int matrix_tpl<ftype>::LPsimplex(int m1,int m2, ftype &objfunout,ftype *xout, int nvars, ftype e) const
{
int M=nRows-2,N=nCols-1,i,j,imax,jmax,iobjfun=M, res=0,iter=(M+N)*8;
ftype rpivot,t;
const int imask=0x7FFFFFFF;
int *irow=new int[M],*icol=new int[N];
#define a (*this)
if (e<0) {
for(i=nRows*nCols-1,e=0;i>=0;i--) e+=data[i];
e *= (ftype)1E-6/(nRows*nCols);
}
if (nvars<0) nvars = N+m1+m2;
if (m1<M) {
iobjfun++;
for(j=0;j<N;j++) {
for(t=0,i=0;i<M;i++) t-=a[i][j];
a[iobjfun][j] = t;
}
}
for(i=0;i<N;i++) icol[i]=i;
for(i=0;i<M;i++) irow[i]=N+i|~imask;
do {
for(t=0,j=0,jmax=-1;j<N;j++) if(icol[j]<nvars && a[iobjfun][j]>t)
{ jmax=j; t=a[iobjfun][j]; }
if (jmax<0)
{ res=1; break; }
for(imax=0; imax<M && a[imax][jmax]>0; imax++);
if (imax==M)
{ res=2; break; }
for(i=imax+1;i<M;i++) if (a[i][jmax]<0 && a[i][N]*a[imax][jmax] < a[imax][N]*a[i][jmax])
imax=i;
varexchange:
rpivot = (ftype)1.0/a[imax][jmax];
for(j=0;j<nCols;j++) a[imax][j]*=-rpivot;
a[imax][jmax] = rpivot;
for(i=0;i<nRows;i++) if(i!=imax) {
a[i][jmax] *= rpivot;
for(j=0;j<nCols;j++) if(j!=jmax)
a[i][j] -= a[imax][j]*a[i][jmax];
}
if ((irow[imax]&imask)>=N+m1 && (irow[imax]&imask)<N+m1+m2 && (irow[imax]&~imask)!=0) {
a[iobjfun][jmax] += 1; // remove slack variable from objective function, nonnegativity constraint will enforce feasibility
for(i=0;i<=M;i++) a[i][jmax]*=-1;
}
i=irow[imax]&imask; irow[imax]=icol[jmax]; icol[jmax]=i;
} while(--iter);
if (m1<M) {
if (res==2 || sqr(a[M][N])<e*e)
res = 0;
else {
for(i=0;i<M;i++) {
if ((irow[i]&imask)>M+m1+m2) {
for(jmax=0;jmax<N && icol[jmax]>=nvars;jmax++);
imax=i; goto varexchange;
} else if ((irow[i]&imask)>N+m1 && (irow[i]&~imask)!=0) {
for(j=0;j<N;j++) a[i][j]*=-1;
irow[i]&=imask;
}
}
res = LPsimplex(M,0, objfunout,xout, nvars, e);
}
} else {
if (xout) {
for(i=0;i<N;i++) xout[i]=0;
for(i=0;i<M;i++) if((irow[i]&imask)<N)
xout[irow[i]&imask] = a[i][N];
}
objfunout = a[iobjfun][N];
}
delete[] irow; delete[] icol;
return res;
#undef a
}
#ifdef PIII_SSE
// TODO: AMD64: put into a separate file
// SSE-optimized code from "Streaming SIMD Extensions - Matrix Multiplication" document by Intel Corp.
__declspec(naked) void PIII_Mult00_6x6_6x6(float *src1, float *src2, float *dst)
{
__asm {
mov ecx, dword ptr [esp+8] // src2
movlps xmm3, qword ptr [ecx+72]
mov edx, dword ptr [esp+4] // src1
// Loading first 4 columns (upper 4 rows) of src2.
movaps xmm0, xmmword ptr [ecx]
movlps xmm1, qword ptr [ecx+24]
movhps xmm1, qword ptr [ecx+32]
movaps xmm2, xmmword ptr [ecx+48]
movhps xmm3, qword ptr [ecx+80]
// Calculating first 4 elements in the first row of the destination matrix.
movss xmm4, dword ptr [edx]
movss xmm5, dword ptr [edx+4]
mov eax, dword ptr [esp+0Ch] // dst
shufps xmm4, xmm4, 0
movss xmm6, dword ptr [edx+8]
shufps xmm5, xmm5, 0
movss xmm7, dword ptr [edx+12]
mulps xmm4, xmm0
shufps xmm6, xmm6, 0
shufps xmm7, xmm7, 0
mulps xmm5, xmm1
mulps xmm6, xmm2
addps xmm5, xmm4
mulps xmm7, xmm3
addps xmm6, xmm5
addps xmm7, xmm6
movaps xmmword ptr [eax], xmm7
// Calculating first 4 elements in the second row of the destination matrix.
movss xmm4, dword ptr [edx+24]
shufps xmm4, xmm4, 0
mulps xmm4, xmm0
movss xmm5, dword ptr [edx+28]
shufps xmm5, xmm5, 0
mulps xmm5, xmm1
movss xmm6, dword ptr [edx+32]
shufps xmm6, xmm6, 0
movss xmm7, dword ptr [edx+36]
shufps xmm7, xmm7, 0
mulps xmm6, xmm2
mulps xmm7, xmm3
addps xmm7, xmm6
addps xmm5, xmm4
addps xmm7, xmm5
// Calculating first 4 elements in the third row of the destination matrix.
movss xmm4, dword ptr [edx+48]
movss xmm5, dword ptr [edx+52]
movlps qword ptr [eax+24], xmm7 // save 2nd
movhps qword ptr [eax+32], xmm7 // row
movss xmm6, dword ptr [edx+56]
movss xmm7, dword ptr [edx+60]
shufps xmm4, xmm4, 0
shufps xmm5, xmm5, 0
shufps xmm6, xmm6, 0
shufps xmm7, xmm7, 0
mulps xmm4, xmm0
mulps xmm5, xmm1
mulps xmm6, xmm2
mulps xmm7, xmm3
addps xmm5, xmm4
addps xmm7, xmm6
addps xmm7, xmm5
movaps xmmword ptr [eax+48], xmm7
// Calculating first 4 elements in the fourth row of the destination matrix.
movss xmm4, dword ptr [edx+72]
movss xmm5, dword ptr [edx+76]
movss xmm6, dword ptr [edx+80]
movss xmm7, dword ptr [edx+84]
shufps xmm4, xmm4, 0
shufps xmm5, xmm5, 0
shufps xmm6, xmm6, 0
shufps xmm7, xmm7, 0
mulps xmm4, xmm0
mulps xmm5, xmm1
mulps xmm6, xmm2
mulps xmm7, xmm3
addps xmm4, xmm5
addps xmm6, xmm4
addps xmm7, xmm6
movlps qword ptr [eax+72], xmm7
movhps qword ptr [eax+80], xmm7
// Calculating first 4 elements in the fifth row of the destination matrix.
movss xmm4, dword ptr [edx+96]
movss xmm5, dword ptr [edx+100]
movss xmm6, dword ptr [edx+104]
movss xmm7, dword ptr [edx+108]
shufps xmm4, xmm4, 0
shufps xmm5, xmm5, 0
shufps xmm6, xmm6, 0
shufps xmm7, xmm7, 0
mulps xmm4, xmm0
mulps xmm5, xmm1
mulps xmm6, xmm2
mulps xmm7, xmm3
addps xmm5, xmm4
addps xmm7, xmm6
addps xmm7, xmm5
movaps xmmword ptr [eax+96], xmm7
// Calculating first 4 elements in the sixth row of the destination matrix.
movss xmm4, dword ptr [edx+120]
movss xmm5, dword ptr [edx+124]
movss xmm6, dword ptr [edx+128]
movss xmm7, dword ptr [edx+132]
shufps xmm4, xmm4, 0
shufps xmm5, xmm5, 0
shufps xmm6, xmm6, 0
shufps xmm7, xmm7, 0
mulps xmm4, xmm0
mulps xmm5, xmm1
mulps xmm6, xmm2
mulps xmm7, xmm3
addps xmm4, xmm5
addps xmm6, xmm4
addps xmm7, xmm6
movhps qword ptr [eax+128], xmm7
movlps qword ptr [eax+120], xmm7
// Loading first 4 columns (lower 2 rows) of src2.
movlps xmm0, qword ptr [ecx+96]
movhps xmm0, qword ptr [ecx+104]
movlps xmm1, qword ptr [ecx+120]
movhps xmm1, qword ptr [ecx+128]
// Calculating first 4 elements in the first row of the destination matrix.
movss xmm2, dword ptr [edx+16]
shufps xmm2, xmm2, 0
movss xmm4, dword ptr [edx+40]
movss xmm3, dword ptr [edx+20]
movss xmm5, dword ptr [edx+44]
movaps xmm6, xmmword ptr [eax]
movlps xmm7, qword ptr [eax+24]
shufps xmm3, xmm3, 0
shufps xmm5, xmm5, 0
movhps xmm7, qword ptr [eax+32]
shufps xmm4, xmm4, 0
mulps xmm5, xmm1
mulps xmm2, xmm0
mulps xmm3, xmm1
mulps xmm4, xmm0
addps xmm6, xmm2
addps xmm7, xmm4
addps xmm7, xmm5
addps xmm6, xmm3
movlps qword ptr [eax+24], xmm7
movaps xmmword ptr [eax], xmm6
movhps qword ptr [eax+32], xmm7
// Calculating first 4 elements in the third row of the destination matrix.
movss xmm2, dword ptr [edx+64]
movss xmm4, dword ptr [edx+88]
movss xmm5, dword ptr [edx+92]
movss xmm3, dword ptr [edx+68]
movaps xmm6, xmmword ptr [eax+48]
movlps xmm7, qword ptr [eax+72]
movhps xmm7, qword ptr [eax+80]
shufps xmm2, xmm2, 0
shufps xmm4, xmm4, 0
shufps xmm5, xmm5, 0
shufps xmm3, xmm3, 0
mulps xmm2, xmm0
mulps xmm4, xmm0
mulps xmm5, xmm1
mulps xmm3, xmm1
addps xmm6, xmm2
addps xmm6, xmm3
addps xmm7, xmm4
addps xmm7, xmm5
movlps qword ptr [eax+72], xmm7
movaps xmmword ptr [eax+48], xmm6
movhps qword ptr [eax+80], xmm7
// Calculating first 4 elements in the fifth row of the destination matrix.
movss xmm2, dword ptr [edx+112]
movss xmm3, dword ptr [edx+116]
movaps xmm6, xmmword ptr [eax+96]
shufps xmm2, xmm2, 0
shufps xmm3, xmm3, 0
mulps xmm2, xmm0
mulps xmm3, xmm1
addps xmm6, xmm2
addps xmm6, xmm3
movaps xmmword ptr [eax+96], xmm6
// Calculating first 4 elements in the sixth row of the destination matrix.
movss xmm4, dword ptr [edx+136]
movss xmm5, dword ptr [edx+140]
movhps xmm7, qword ptr [eax+128]
movlps xmm7, qword ptr [eax+120]
shufps xmm4, xmm4, 0
shufps xmm5, xmm5, 0
mulps xmm4, xmm0
mulps xmm5, xmm1
addps xmm7, xmm4
addps xmm7, xmm5
// Calculating last 2 columns of the destination matrix.
movlps xmm0, qword ptr [ecx+16]
movhps xmm0, qword ptr [ecx+40]
movhps qword ptr [eax+128], xmm7
movlps qword ptr [eax+120], xmm7
movlps xmm2, qword ptr [ecx+64]
movhps xmm2, qword ptr [ecx+88]
movaps xmm3, xmm2
shufps xmm3, xmm3, 4Eh
movlps xmm4, qword ptr [ecx+112]
movhps xmm4, qword ptr [ecx+136]
movaps xmm5, xmm4
shufps xmm5, xmm5, 4Eh
movlps xmm6, qword ptr [edx]
movhps xmm6, qword ptr [edx+24]
movaps xmm7, xmm6
shufps xmm7, xmm7, 0F0h
mulps xmm7, xmm0
shufps xmm6, xmm6, 0A5h
movaps xmm1, xmm0
shufps xmm1, xmm1, 4Eh
mulps xmm1, xmm6
addps xmm7, xmm1
movlps xmm6, qword ptr [edx+8]
movhps xmm6, qword ptr [edx+32]
movaps xmm1, xmm6
shufps xmm1, xmm1, 0F0h
shufps xmm6, xmm6, 0A5h
mulps xmm1, xmm2
mulps xmm6, xmm3
addps xmm7, xmm1
addps xmm7, xmm6
movhps xmm6, qword ptr [edx+40]
movlps xmm6, qword ptr [edx+16]
movaps xmm1, xmm6
shufps xmm1, xmm1, 0F0h
shufps xmm6, xmm6, 0A5h
mulps xmm1, xmm4
mulps xmm6, xmm5
addps xmm7, xmm1
addps xmm7, xmm6
movlps qword ptr [eax+16], xmm7
movhps qword ptr [eax+40], xmm7
movlps xmm6, qword ptr [edx+48]
movhps xmm6, qword ptr [edx+72]
movaps xmm7, xmm6
shufps xmm7, xmm7, 0F0h
mulps xmm7, xmm0
shufps xmm6, xmm6, 0A5h
movaps xmm1, xmm0
shufps xmm1, xmm1, 4Eh
mulps xmm1, xmm6
addps xmm7, xmm1
movhps xmm6, qword ptr [edx+80]
movlps xmm6, qword ptr [edx+56]
movaps xmm1, xmm6
shufps xmm1, xmm1, 0F0h
shufps xmm6, xmm6, 0A5h
mulps xmm1, xmm2
mulps xmm6, xmm3
addps xmm7, xmm1
addps xmm7, xmm6
movlps xmm6, qword ptr [edx+64]
movhps xmm6, qword ptr [edx+88]
movaps xmm1, xmm6
shufps xmm1, xmm1, 0F0h
shufps xmm6, xmm6, 0A5h
mulps xmm1, xmm4
mulps xmm6, xmm5
addps xmm7, xmm1
addps xmm7, xmm6
movlps qword ptr [eax+64], xmm7
movhps qword ptr [eax+88], xmm7
movlps xmm6, qword ptr [edx+96]
movhps xmm6, qword ptr [edx+120]
movaps xmm7, xmm6
shufps xmm7, xmm7, 0F0h
mulps xmm7, xmm0
shufps xmm6, xmm6, 0A5h
movaps xmm1, xmm0
shufps xmm1, xmm1, 4Eh
mulps xmm1, xmm6
addps xmm7, xmm1
movlps xmm6, qword ptr [edx+104]
movhps xmm6, qword ptr [edx+128]
movaps xmm1, xmm6
shufps xmm1, xmm1, 0F0h
shufps xmm6, xmm6, 0A5h
mulps xmm1, xmm2
mulps xmm6, xmm3
addps xmm7, xmm1
addps xmm7, xmm6
movlps xmm6, qword ptr [edx+112]
movhps xmm6, qword ptr [edx+136]
movaps xmm1, xmm6
shufps xmm1, xmm1, 0F0h
shufps xmm6, xmm6, 0A5h
mulps xmm1, xmm4
mulps xmm6, xmm5
addps xmm7, xmm1
addps xmm7, xmm6
movlps qword ptr [eax+112], xmm7
movhps qword ptr [eax+136], xmm7
ret }
}
#endif
void ForceCompilerToGenerateCodeForMatrixTemplates()
{
matrixf mtxf; float f,*pf; int *pi;
mtxf.jacobi_transformation(mtxf,0);
mtxf.conjugate_gradient(0,0);
mtxf.biconjugate_gradient(0,0);
mtxf.minimum_residual(0,0);
mtxf.LPsimplex(0,0,f);
mtxf.LUdecomposition(pf,pi);
mtxf.solveAx_b(pf,pf);
mtxf.determinant();
mtxf.invert();
matrix mtxr; real r,*pr;
mtxr.jacobi_transformation(mtxr,0);
mtxr.conjugate_gradient(0,0);
mtxr.biconjugate_gradient(0,0);
mtxr.minimum_residual(0,0);
mtxr.LPsimplex(0,0,r);
mtxr.LUdecomposition(pr,pi);
mtxr.solveAx_b(pr,pr);
mtxr.determinant();
mtxr.invert();
}

276
CryPhysics/matrixnm.h Normal file
View File

@@ -0,0 +1,276 @@
//////////////////////////////////////////////////////////////////////
//
// NxM Matrix header
//
// File: matrixnm.h
// Description : matrixnm template class declaration and inlined implementation
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#ifndef matrixnm_h
#define matrixnm_h
#pragma once
enum mtxflags {
mtx_invalid=1, mtx_normal=2, mtx_orthogonal=4, mtx_PSD=8, mtx_PD_flag=16, mtx_PD=mtx_PSD|mtx_PD_flag, mtx_symmetric=32,
mtx_diagonal_flag=64, mtx_diagonal=mtx_symmetric|mtx_normal|mtx_diagonal_flag, mtx_identity_flag=128,
mtx_identity=mtx_PD|mtx_diagonal|mtx_orthogonal|mtx_normal|mtx_symmetric|mtx_identity_flag, mtx_singular=256,
mtx_foreign_data=1024, // this flag means that data was not allocated by matrix
mtx_allocate=32768 // prohibts using matrix pool for data
};
template<class ftype> class matrix_product_tpl {
public:
matrix_product_tpl(int nrows1,int ncols1,ftype *pdata1,int flags1, int ncols2,ftype *pdata2,int flags2) {
data1=pdata1; data2=pdata2; nRows1=nrows1;nCols1=ncols1; nCols2=ncols2;
flags = flags1 & flags2 & (mtx_orthogonal | mtx_PD) & ~mtx_foreign_data;
}
void assign_to(ftype *pdst) const {
int i,j,k; ftype sum;
for(i=0;i<nRows1;i++) for(j=0;j<nCols2;j++) {
for(sum=0,k=0; k<nCols1; k++)
sum += data1[i*nCols1+k]*data2[k*nCols2+j];
pdst[i*nCols2+j] = sum;
}
}
void add_assign_to(ftype *pdst) const {
for(int i=0;i<nRows1;i++) for(int j=0;j<nCols2;j++)
for(int k=0; k<nCols1; k++)
pdst[i*nCols2+j] += data1[i*nCols1+k]*data2[k*nCols2+j];
}
void sub_assign_to(ftype *pdst) const {
for(int i=0;i<nRows1;i++) for(int j=0;j<nCols2;j++)
for(int k=0; k<nCols1; k++)
pdst[i*nCols2+j] -= data1[i*nCols1+k]*data2[k*nCols2+j];
}
int nRows1,nCols1,nCols2;
ftype *data1,*data2;
int flags;
};
template <class ftype> class matrix_tpl {
public:
matrix_tpl() {
nRows=nCols=3; flags=mtx_foreign_data; data=0;
}
matrix_tpl( int nrows, int ncols, int _flags=0, ftype *pdata=(ftype*)-1 ) {
nRows = nrows; nCols = ncols;
flags = _flags & ~mtx_allocate;
int sz = nRows*nCols;
if (pdata!=(ftype*)-1) {
data = pdata; flags |= mtx_foreign_data;
#ifdef USE_MATRIX_POOLS
} else if (sz<=36 && !(_flags & mtx_allocate)) {
if (mtx_pool_pos+sz > mtx_pool_size)
mtx_pool_pos = 0;
data = mtx_pool+mtx_pool_pos;
mtx_pool_pos += sz;
flags |= mtx_foreign_data;
#endif
} else
data = new ftype[sz];
}
matrix_tpl(const matrix_tpl& src) {
if (src.flags & mtx_foreign_data) {
nRows=src.nRows; nCols=src.nCols;
flags=src.flags; data=src.data;
} else {
matrix_tpl(src.nRows,src.nCols,src.flags,0);
for(int i=nRows*nCols-1;i>=0;i--) data[i]=src.data[i];
}
}
~matrix_tpl() {
if (data && !(flags & mtx_foreign_data)) delete [] data;
}
matrix_tpl& operator=(const matrix_tpl<ftype> &src) {
if (!data || !(flags & mtx_foreign_data) && nRows*nCols<src.nRows*src.nCols) {
delete[] data; data = new ftype[src.nRows*src.nCols];
}
nRows=src.nRows; nCols=src.nCols;
flags = flags&mtx_foreign_data | src.flags&~mtx_foreign_data;
for(int i=nRows*nCols-1;i>=0;i--) data[i] = src.data[i];
return *this;
}
template<class ftype1> matrix_tpl& operator=(const matrix_tpl<ftype1> &src) {
if (!data || !(flags & mtx_foreign_data) && nRows*nCols<src.nRows*src.nCols) {
delete[] data; data = new ftype[src.nRows*src.nCols];
}
nRows=src.nRows; nCols=src.nCols;
flags = flags&mtx_foreign_data | src.flags&~mtx_foreign_data;
for(int i=nRows*nCols-1;i>=0;i--) data[i] = src.data[i];
return *this;
}
matrix_tpl& operator=(const matrix_product_tpl<ftype> &src) {
nRows=src.nRows1; nCols=src.nCols2;
flags = flags&mtx_foreign_data | src.flags;
src.assign_to(data);
return *this;
}
matrix_tpl& operator+=(const matrix_product_tpl<ftype> &src) {
src.add_assign_to(data); return *this;
}
matrix_tpl& operator-=(const matrix_product_tpl<ftype> &src) {
src.sub_assign_to(data); return *this;
}
matrix_tpl& allocate() {
int i,sz=nRows*nCols; ftype *prevdata = data;
if (!data) data = new ftype[sz];
if (flags & mtx_foreign_data) for(i=0;i<sz;i++) data[i] = prevdata[i];
return *this;
}
matrix_tpl& zero() { for(int i=nRows*nCols-1;i>=0;i--) data[i]=0; return *this; }
matrix_tpl& identity() {
zero(); for(int i=min(nRows,nCols)-1;i>=0;i--) data[i*(nCols+1)] = 1;
return *this;
}
matrix_tpl& invert(); // in-place inversion
matrix_tpl operator!() const { // returns inverted matrix
if (flags & mtx_orthogonal)
return T();
matrix_tpl<ftype> res = *this;
res.invert();
return res;
}
matrix_tpl& transpose() { // in-place transposition
if (nRows==nCols) {
if (flags & mtx_symmetric) return *this;
int i,j; ftype t; for(i=0;i<nRows;i++) for(j=0;j<i;j++) {
t=(*this)[i][j]; (*this)[i][j]=(*this)[j][i]; (*this)[j][i]=t;
}
} else
*this = T();
return *this;
}
matrix_tpl T() const { // returns transposed matrix
if (flags & mtx_symmetric)
return matrix_tpl<ftype>(*this);
int i,j; matrix_tpl<ftype> res(nCols,nRows, flags & ~mtx_foreign_data);
for(i=0;i<nRows;i++) for(j=0;j<nCols;j++) res[j][i] = (*this)[i][j];
return res;
}
int LUdecomposition(ftype *&LUdata,int *&LUidx) const;
int solveAx_b(ftype *x,ftype *b, ftype *LUdata=0,int *LUidx=0) const; // finds x that satisfies Ax=b
ftype determinant(ftype *LUdata=0,int *LUidx=0) const;
int jacobi_transformation(matrix_tpl &evec, ftype* eval, ftype prec=0) const;
int conjugate_gradient(ftype *startx,ftype *rightside, ftype minlen=0,ftype minel=0) const;
int biconjugate_gradient(ftype *startx,ftype *rightside, ftype minlen=0,ftype minel=0) const;
int minimum_residual(ftype *startx,ftype *rightside, ftype minlen=0,ftype minel=0) const;
int LPsimplex(int m1,int m2, ftype &objfunout,ftype *xout=0, int nvars=-1, ftype e=-1) const;
ftype *operator[](int iRow) const { return data + iRow*nCols; }
int nRows,nCols;
int flags;
ftype *data;
#ifdef USE_MATRIX_POOLS
static ftype mtx_pool[];
static int mtx_pool_pos;
static int mtx_pool_size;
#endif
};
/*template<class ftype1,class ftype2>
matrix_tpl<ftype1> operator*(const matrix_tpl<ftype1> &op1, const matrix_tpl<ftype2> &op2) {
matrix_tpl<ftype1> res(op1.nRows, op2.nCols);
res.flags = res.flags & mtx_foreign_data | op1.flags & op2.flags & (mtx_orthogonal | mtx_PD) & ~mtx_foreign_data;
int i,j,k; ftype1 sum;
for(i=0;i<op1.nRows;i++) for(j=0;j<op2.nCols;j++) {
for(sum=0,k=0; k<op1.nCols; k++) sum += op1[i][k]*op2[k][j];
res[i][j] = sum;
}
return res;
}*/
template<class ftype>
matrix_product_tpl<ftype> operator*(const matrix_tpl<ftype> &op1, const matrix_tpl<ftype> &op2) {
return matrix_product_tpl<ftype>(op1.nRows,op1.nCols,op1.data,op1.flags, op2.nCols,op2.data,op2.flags);
}
/*template<class ftype1,class ftype2>
matrix_tpl<ftype1>& operator*=(matrix_tpl<ftype1> &op1, const matrix_tpl<ftype2> &op2) {
return op1 = (op1 * op2);
}*/
template<class ftype>
matrix_tpl<ftype>& operator*=(matrix_tpl<ftype> &op1,ftype op2) {
for(int i=op1.nRows*op1.nCols-1; i>=0; i--) op1.data[i]*=op2;
op1.flags &= ~(mtx_identity_flag | mtx_PD);
return op1;
}
template<class ftype1,class ftype2>
matrix_tpl<ftype1>& operator+=(matrix_tpl<ftype1> &op1, const matrix_tpl<ftype2> &op2) {
for(int i=op1.nRows*op1.nCols-1; i>=0; i--) op1.data[i] += op2.data[i];
op1.flags = op1.flags & mtx_foreign_data | op1.flags & op2.flags & (mtx_symmetric | mtx_PD);
return op1;
}
template<class ftype1,class ftype2>
matrix_tpl<ftype1>& operator-=(matrix_tpl<ftype1> &op1, const matrix_tpl<ftype2> &op2) {
for(int i=op1.nRows*op1.nCols-1; i>=0; i--) op1.data[i] -= op2.data[i];
op1.flags = op1.flags & mtx_foreign_data | op1.flags & op2.flags & mtx_symmetric;
return op1;
}
template<class ftype1,class ftype2>
matrix_tpl<ftype1> operator+(const matrix_tpl<ftype1> &op1, const matrix_tpl<ftype2> &op2) {
matrix_tpl<ftype1> res; res=op1; res+=op2;
return res;
}
template<class ftype1,class ftype2>
matrix_tpl<ftype1> operator-(const matrix_tpl<ftype1> &op1, const matrix_tpl<ftype2> &op2) {
matrix_tpl<ftype1> res; res=op1; res-=op2;
return res;
}
template<class ftype1,class ftype2,class ftype3>
ftype3 *mul_vector_by_matrix(const matrix_tpl<ftype1> &mtx, const ftype2 *psrc,ftype3 *pdst) {
int i,j;
for(i=0;i<mtx.nRows;i++) for(pdst[i]=0,j=0;j<mtx.nCols;j++)
pdst[i] += mtx.data[i*mtx.nCols+j]*psrc[j];
return pdst;
}
typedef matrix_tpl<real> matrix;
typedef matrix_tpl<float> matrixf;
#if defined(LINUX)
#define DECLARE_MTXNxM_POOL(ftype,sz) template<> ftype matrix_tpl<ftype>::mtx_pool[sz] = {}; template<> int matrix_tpl<ftype>::mtx_pool_pos=0; \
template<> int matrix_tpl<ftype>::mtx_pool_size=sz;
#else
#define DECLARE_MTXNxM_POOL(ftype,sz) template<> ftype matrix_tpl<ftype>::mtx_pool[sz]; template<> int matrix_tpl<ftype>::mtx_pool_pos=0; \
template<> int matrix_tpl<ftype>::mtx_pool_size=sz;
#endif //LINUX
extern int g_bHasSSE;
#ifdef PIII_SSE
void PIII_Mult00_6x6_6x6(float *src1, float *src2, float *dst);
inline void matrix_product_tpl<float>::assign_to(float *pdst) const {
if ((g_bHasSSE^1|nRows1-6|nCols1-6|nCols2-6)==0)
PIII_Mult00_6x6_6x6(data1,data2, pdst);
else {
int i,j,k; float sum;
for(i=0;i<nRows1;i++) for(j=0;j<nCols2;j++) {
for(sum=0,k=0; k<nCols1; k++)
sum += data1[i*nCols1+k]*data2[k*nCols2+j];
pdst[i*nCols2+j] = sum;
}
}
}
#endif
#endif

428
CryPhysics/obbtree.cpp Normal file
View File

@@ -0,0 +1,428 @@
#include "stdafx.h"
#include "utils.h"
#include "primitives.h"
#include "bvtree.h"
#include "geometry.h"
#include "obbtree.h"
#include "trimesh.h"
void COBBTree::SetParams(int nMinTrisPerNode, int nMaxTrisPerNode, float skipdim)
{
m_nMinTrisPerNode = nMinTrisPerNode; m_nMaxTrisPerNode = nMaxTrisPerNode;
m_maxSkipDim = skipdim;
}
float COBBTree::Build(CGeometry *pMesh)
{
m_pMesh = (CTriMesh*)pMesh;
m_pNodes = new OBBnode[m_nNodesAlloc=256];
memset(m_pMapVtxUsed = new int[(m_pMesh->m_nVertices-1>>5)+1], 0, (m_pMesh->m_nVertices-1>>3)+1);
m_pVtxUsed = new vectorf[m_pMesh->m_nVertices];
m_pNodes[0].iparent = -1;
m_pTri2Node = new index_t[m_pMesh->m_nTris];
m_nMaxTrisInNode = 0;
m_nNodes = 2;
m_pNodes[0].iparent = m_pNodes[1].iparent = -1;
m_pNodes[0].ntris = m_pNodes[1].ntris = 0;
float volume = BuildNode(0, 0,m_pMesh->m_nTris, 0);
if (m_nNodesAlloc>m_nNodes) {
OBBnode *pNodes = m_pNodes;
memcpy(m_pNodes = new OBBnode[m_nNodesAlloc=m_nNodes], pNodes, sizeof(OBBnode)*m_nNodes);
delete[] pNodes;
}
delete[] m_pMapVtxUsed;
delete[] m_pVtxUsed;
m_maxSkipDim *= max(max(m_pNodes[0].size.x,m_pNodes[0].size.y),m_pNodes[0].size.z);
return volume*8;
}
float COBBTree::BuildNode(int iNode, int iTriStart,int nTris, int nDepth)
{
int nHullTris,i,j,nPts,iStart=1<<30,iEnd=-1,idx0=iTriStart*3,nidx=nTris*3;
index_t *pHullTris=0;
// calculate convex hull of vertices
// mark all vertices used by this set of triangles
for(i=0; i<nidx; i++) {
m_pMapVtxUsed[m_pMesh->m_pIndices[idx0+i]>>5] |= 1<<(m_pMesh->m_pIndices[idx0+i]&31);
iStart = min(iStart, m_pMesh->m_pIndices[idx0+i]);
iEnd = max(iEnd, m_pMesh->m_pIndices[idx0+i]);
}
// group these vertices in one array
for(i=iStart,nPts=0; i<=iEnd; i++) if (m_pMapVtxUsed[i>>5] & 1<<(i&31)) {
m_pVtxUsed[nPts++]=m_pMesh->m_pVertices[i]; m_pMapVtxUsed[i>>5] &= ~(1<<(i&31));
}
// give these vertices to qhull routine
if (nDepth>4 || nTris<50 || !(nHullTris = qhull(m_pVtxUsed,nPts, pHullTris))) {
nHullTris=nTris; pHullTris=m_pMesh->m_pIndices+idx0;
}
vectorr axes[3],mean;
matrix3x3 Basis;
if (nHullTris) {
ComputeMeshEigenBasis(m_pMesh->m_pVertices,pHullTris,nHullTris, axes,mean);
Basis = (matrix3x3RM&)axes[0];
} else // convex hull not computed. probably we have some degenerate case, so use AABB
Basis.SetIdentity();
if (pHullTris && pHullTris!=m_pMesh->m_pIndices+idx0)
delete[] pHullTris;
// calculate bounding box center and dimensions
vectorr pt,ptmin(MAX),ptmax(MIN);
for(i=0;i<nPts;i++) {
pt = Basis*m_pVtxUsed[i];
for(j=0;j<3;j++) {
ptmin[j] = min_safe(ptmin[j], pt[j]);
ptmax[j] = max_safe(ptmax[j], pt[j]);
}
}
(matrix3x3RMf&)m_pNodes[iNode].axes[0] = Basis;
m_pNodes[iNode].size = (ptmax-ptmin)*0.5f;
m_pNodes[iNode].center = ((ptmax+ptmin)*(real)0.5)*Basis;
float mindim = max(max(m_pNodes[iNode].size.x,m_pNodes[iNode].size.y),m_pNodes[iNode].size.z)*0.001f;
for(i=0;i<3;i++) {
m_pNodes[iNode].axes[i] = axes[i];
m_pNodes[iNode].size[i] = max(mindim, m_pNodes[iNode].size[i]);
}
if (nTris<=m_nMaxTrisPerNode) {
m_pNodes[iNode].ichild = iTriStart;
m_pNodes[iNode].ntris = nTris;
m_nMaxTrisInNode = max(m_nMaxTrisInNode, nTris);
for(i=iTriStart;i<iTriStart+nTris;i++)
m_pTri2Node[i] = iNode;
return m_pNodes[iNode].size.volume();
}
// separate geometry into two parts
#if defined(WIN64) || defined(LINUX64)
volatile // compiler bug workaround?
#endif
int iAxis;
int numtris[3],nTrisAx[3],iPart,iMode[3],idx;
float x0,x1,x2,cx,sz,xlim[2],bounds[3][2],diff[3],axdiff[3];
vectorf axis,center;
for(iAxis=0;iAxis<3;iAxis++) {
sz = m_pNodes[iNode].size[iAxis];
if (sz<mindim*10) {
axdiff[iAxis] = -1E10f; nTrisAx[iAxis] = 0;
continue;
}
axis = m_pNodes[iNode].axes[iAxis];
cx = axis*m_pNodes[iNode].center;
bounds[0][0]=bounds[1][0]=bounds[2][0] = -sz;
bounds[0][1]=bounds[1][1]=bounds[2][1] = sz;
numtris[0]=numtris[1]=numtris[2] = 0;
for(i=iTriStart;i<iTriStart+nTris;i++) {
center = m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3]]+m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3+1]]+
m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3+2]];
x0 = m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3+0]]*axis-cx;
x1 = m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3+1]]*axis-cx;
x2 = m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3+2]]*axis-cx;
xlim[0] = min(min(x0,x1),x2); xlim[1] = max(max(x0,x1),x2);
/*for(j=0,center.zero(),xlim[0]=sz,xlim[1]=-sz;j<3;j++) {
center += m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3+j]];
x = axis*m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3+j]]-cx;
xlim[0] = min(xlim[0],x); xlim[1] = max(xlim[1],x);
}*/
iPart = isneg(xlim[1])^1; // mode0: group all triangles that are entirely below center
bounds[0][iPart] = minmax(bounds[0][iPart],xlim[iPart^1],iPart^1); numtris[0]+=iPart;
iPart = isnonneg(xlim[0]); // mode1: group all triangles that are entirely above center
bounds[1][iPart] = minmax(bounds[1][iPart],xlim[iPart^1],iPart^1); numtris[1]+=iPart;
iPart = isnonneg(((center*axis)*(1.0f/3)-cx)); // mode2: sort triangles basing on centroids only
bounds[2][iPart] = minmax(bounds[2][iPart],xlim[iPart^1],iPart^1); numtris[2]+=iPart;
}
for(i=0;i<3;i++) diff[i] = bounds[i][1]-bounds[i][0]-sz*(isneg(numtris[i]-m_nMinTrisPerNode)|isneg(nTris-numtris[i]-m_nMinTrisPerNode));
iMode[iAxis] = idxmax3(diff); nTrisAx[iAxis] = numtris[iMode[iAxis]];
axdiff[iAxis] = diff[iMode[iAxis]]*m_pNodes[iNode].size[dec_mod3[iAxis]]*m_pNodes[iNode].size[inc_mod3[iAxis]];
}
iAxis = idxmax3(axdiff);
axis = m_pNodes[iNode].axes[iAxis];
cx = axis*m_pNodes[iNode].center;
for(i=j=iTriStart;i<iTriStart+nTris;i++) {
x0 = m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3+0]]*axis-cx;
x1 = m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3+1]]*axis-cx;
x2 = m_pMesh->m_pVertices[m_pMesh->m_pIndices[i*3+2]]*axis-cx;
#if 0//def WIN64
if ((unsigned)iAxis >= 3)
OutputDebugString ("iAxis>=3!");
else
if ((unsigned)iMode[iAxis] >= 3)
OutputDebugString("iMode[iAxis]>=3!");
#endif
switch(iMode[iAxis]) {
case 0: iPart = isneg(max(max(x0,x1),x2))^1; break;
case 1: iPart = isnonneg(min(min(x0,x1),x2)); break;
case 2: iPart = isnonneg(x0+x1+x2);
}
if (iPart==0) {
// swap triangles
idx=m_pMesh->m_pIndices[i*3+0]; m_pMesh->m_pIndices[i*3+0]=m_pMesh->m_pIndices[j*3+0]; m_pMesh->m_pIndices[j*3+0]=idx;
idx=m_pMesh->m_pIndices[i*3+1]; m_pMesh->m_pIndices[i*3+1]=m_pMesh->m_pIndices[j*3+1]; m_pMesh->m_pIndices[j*3+1]=idx;
idx=m_pMesh->m_pIndices[i*3+2]; m_pMesh->m_pIndices[i*3+2]=m_pMesh->m_pIndices[j*3+2]; m_pMesh->m_pIndices[j*3+2]=idx;
if (m_pMesh->m_pIds) {
idx=m_pMesh->m_pIds[i]; m_pMesh->m_pIds[i]=m_pMesh->m_pIds[j]; m_pMesh->m_pIds[j]=idx;
}
j++;
}
}
j -= iTriStart;
if (j<m_nMinTrisPerNode || j>nTris-m_nMinTrisPerNode) {
m_pNodes[iNode].ichild = iTriStart;
m_pNodes[iNode].ntris = nTris;
m_nMaxTrisInNode = max(m_nMaxTrisInNode, nTris);
for(i=iTriStart;i<iTriStart+nTris;i++)
m_pTri2Node[i] = iNode;
return m_pNodes[iNode].size.volume();
}
// proceed with the children
if (m_nNodes+2 > m_nNodesAlloc) {
OBBnode *pNodes = m_pNodes;
memcpy(m_pNodes = new OBBnode[m_nNodesAlloc+=256], pNodes, m_nNodes*sizeof(OBBnode));
delete[] pNodes;
}
m_pNodes[iNode].ichild = m_nNodes;
m_pNodes[m_nNodes].iparent = m_pNodes[m_nNodes+1].iparent = iNode;
m_pNodes[m_nNodes].ntris = m_pNodes[m_nNodes+1].ntris = 0;
iNode = m_nNodes; m_nNodes += 2;
float res = BuildNode(iNode+1, iTriStart+j,nTris-j, nDepth+1);
res += BuildNode(iNode, iTriStart,j, nDepth+1);
return res;
}
void COBBTree::SetGeomConvex()
{
m_maxSkipDim = (m_pNodes[0].size.x+m_pNodes[0].size.y+m_pNodes[0].size.z)*10.0f;
}
void COBBTree::GetBBox(box *pbox)
{
pbox->Basis = (matrix3x3RMf&)m_pNodes[0].axes[0];
pbox->bOriented = 1;
pbox->center = m_pNodes[0].center;
pbox->size = m_pNodes[0].size;
}
void COBBTree::GetNodeBV(BV *&pBV,int iNode)
{
pBV = g_BBoxBuf + g_BBoxBufPos++;
pBV->type = box::type;
((BBox*)pBV)->iNode = iNode;
((BBox*)pBV)->abox.Basis = (matrix3x3RMf&)m_pNodes[iNode].axes[0];
((BBox*)pBV)->abox.bOriented = 1;
((BBox*)pBV)->abox.center = m_pNodes[iNode].center;
((BBox*)pBV)->abox.size = m_pNodes[iNode].size;
}
void COBBTree::GetNodeBV(BV *&pBV, const vectorf &sweepdir,float sweepstep, int iNode)
{
pBV = g_BBoxBuf + g_BBoxBufPos++;
pBV->type = box::type;
((BBox*)pBV)->iNode = iNode;
box boxstatic;
boxstatic.Basis = (matrix3x3RMf&)m_pNodes[iNode].axes[0];
boxstatic.bOriented = 1;
boxstatic.center = m_pNodes[iNode].center;
boxstatic.size = m_pNodes[iNode].size;
ExtrudeBox(&boxstatic, sweepdir,sweepstep, &((BBox*)pBV)->abox);
}
void COBBTree::GetNodeBV(const matrix3x3f &Rw,const vectorf &offsw,float scalew, BV *&pBV, int iNode)
{
pBV = g_BBoxBuf + g_BBoxBufPos++;
pBV->type = box::type;
pBV->iNode = iNode;
((BBox*)pBV)->abox.Basis = (matrix3x3RMf&)m_pNodes[iNode].axes[0]*Rw.T();
((BBox*)pBV)->abox.bOriented = 1;
((BBox*)pBV)->abox.center = Rw*m_pNodes[iNode].center*scalew + offsw;
((BBox*)pBV)->abox.size = m_pNodes[iNode].size*scalew;
}
float COBBTree::SplitPriority(const BV* pBV)
{
BBox *pbox = (BBox*)pBV;
return pbox->abox.size.volume()*(m_pNodes[pbox->iNode].ntris-1>>31 & 1);
}
void COBBTree::GetNodeChildrenBVs(const matrix3x3f &Rw,const vectorf &offsw,float scalew,
const BV *pBV_parent, BV *&pBV_child1,BV *&pBV_child2)
{
BBox *bbox_parent=(BBox*)pBV_parent, *&bbox_child1=(BBox*&)pBV_child1, *&bbox_child2=(BBox*&)pBV_child2;
bbox_child1 = g_BBoxBuf + g_BBoxBufPos++;
bbox_child2 = g_BBoxBuf + g_BBoxBufPos++;
bbox_child2->iNode = (bbox_child1->iNode = m_pNodes[bbox_parent->iNode].ichild)+1;
bbox_child1->type = bbox_child2->type = box::type;
OBBnode *pNode = m_pNodes + bbox_child1->iNode;
bbox_child1->abox.Basis = (matrix3x3RMf&)pNode->axes[0]*Rw.T();
bbox_child1->abox.bOriented = 1+bbox_child1->iNode;
bbox_child1->abox.center = Rw*pNode->center*scalew + offsw;
bbox_child1->abox.size = pNode++->size*scalew;
bbox_child2->abox.Basis = (matrix3x3RMf&)pNode->axes[0]*Rw.T();
bbox_child2->abox.bOriented = 1+bbox_child2->iNode;
bbox_child2->abox.center = Rw*pNode->center*scalew + offsw;
bbox_child2->abox.size = pNode->size*scalew;
}
void COBBTree::GetNodeChildrenBVs(const BV *pBV_parent, BV *&pBV_child1,BV *&pBV_child2)
{
BBox *bbox_parent=(BBox*)pBV_parent, *&bbox_child1=(BBox*&)pBV_child1, *&bbox_child2=(BBox*&)pBV_child2;
bbox_child1 = g_BBoxBuf + g_BBoxBufPos++;
bbox_child2 = g_BBoxBuf + g_BBoxBufPos++;
bbox_child2->iNode = (bbox_child1->iNode = m_pNodes[bbox_parent->iNode].ichild)+1;
bbox_child1->type = bbox_child2->type = box::type;
OBBnode *pNode = m_pNodes + bbox_child1->iNode;
bbox_child1->abox.Basis = (matrix3x3RMf&)pNode->axes[0];
bbox_child1->abox.bOriented = 1+bbox_child1->iNode;
bbox_child1->abox.center = pNode->center;
bbox_child1->abox.size = pNode++->size;
bbox_child2->abox.Basis = (matrix3x3RMf&)pNode->axes[0];
bbox_child2->abox.bOriented = 1+bbox_child2->iNode;
bbox_child2->abox.center = pNode->center;
bbox_child2->abox.size = pNode->size;
}
void COBBTree::GetNodeChildrenBVs(const BV *pBV_parent, const vectorf &sweepdir,float sweepstep, BV *&pBV_child1,BV *&pBV_child2)
{
BBox *bbox_parent=(BBox*)pBV_parent, *&bbox_child1=(BBox*&)pBV_child1, *&bbox_child2=(BBox*&)pBV_child2;
bbox_child1 = g_BBoxBuf + g_BBoxBufPos++;
bbox_child2 = g_BBoxBuf + g_BBoxBufPos++;
bbox_child2->iNode = (bbox_child1->iNode = m_pNodes[bbox_parent->iNode].ichild)+1;
bbox_child1->type = bbox_child2->type = box::type;
OBBnode *pNode = m_pNodes + bbox_child1->iNode;
box boxstatic;
boxstatic.bOriented = 1;
boxstatic.Basis = (matrix3x3RMf&)pNode->axes[0];
boxstatic.center = pNode->center;
boxstatic.size = pNode++->size;
ExtrudeBox(&boxstatic, sweepdir,sweepstep, &bbox_child1->abox);
bbox_child1->abox.bOriented = 1+bbox_child1->iNode;
boxstatic.Basis = (matrix3x3RMf&)pNode->axes[0];
boxstatic.center = pNode->center;
boxstatic.size = pNode->size;
ExtrudeBox(&boxstatic, sweepdir,sweepstep, &bbox_child2->abox);
bbox_child1->abox.bOriented = 1+bbox_child2->iNode;
}
void COBBTree::ReleaseLastBVs()
{
g_BBoxBufPos-=2;
}
void COBBTree::ReleaseLastSweptBVs()
{
g_BBoxBufPos-=2;
}
int COBBTree::GetNodeContents(int iNode, BV *pBVCollider,int bColliderUsed,int bColliderLocal, geometry_under_test *pGTest,
geometry_under_test *pGTestOp)
{
return m_pMesh->GetPrimitiveList(m_pNodes[iNode].ichild,m_pNodes[iNode].ntris, pBVCollider->type,*pBVCollider,bColliderLocal, pGTest,pGTestOp,
pGTest->primbuf,pGTest->idbuf);
}
void COBBTree::MarkUsedTriangle(int itri, geometry_under_test *pGTest)
{
if (!pGTest->pUsedNodesMap) return;
int iNode = m_pTri2Node[itri];
if (!(pGTest->pUsedNodesMap[iNode>>5] & 1<<(iNode&31)) &&
max(max(m_pNodes[iNode].size.x,m_pNodes[iNode].size.y),m_pNodes[iNode].size.z) < m_maxSkipDim)
{
do {
pGTest->pUsedNodesMap[iNode>>5] |= 1<<(iNode&31);
pGTest->pUsedNodesIdx[pGTest->nUsedNodes = min(pGTest->nUsedNodes+1,pGTest->nMaxUsedNodes-1)] = iNode;
pGTest->bCurNodeUsed = 1;
iNode ^= 1; // the other child of the same parent
if (!(pGTest->pUsedNodesMap[iNode>>5] & 1<<(iNode&31)))
break;
iNode = m_pNodes[iNode].iparent;
} while (iNode>=0);
}
}
int COBBTree::PrepareForIntersectionTest(geometry_under_test *pGTest)
{
if (m_maxSkipDim<=0) {
pGTest->pUsedNodesMap = 0;
pGTest->pUsedNodesIdx = 0;
pGTest->nMaxUsedNodes = 0;
} else {
int mapsz = (m_nNodes-1>>5) + 1;
if (mapsz<=(int)(sizeof(g_UsedNodesMap)/sizeof(g_UsedNodesMap[0]))-g_UsedNodesMapPos) {
pGTest->pUsedNodesMap = g_UsedNodesMap+g_UsedNodesMapPos; g_UsedNodesMapPos += mapsz;
} else
pGTest->pUsedNodesMap = new int[mapsz];
pGTest->pUsedNodesIdx = g_UsedNodesIdx+g_UsedNodesIdxPos;
pGTest->nMaxUsedNodes = min(32,sizeof(g_UsedNodesIdx)/sizeof(g_UsedNodesIdx[0])-g_UsedNodesIdxPos);
g_UsedNodesIdxPos += pGTest->nMaxUsedNodes;
}
pGTest->nUsedNodes = -1;
return 1;
}
void COBBTree::CleanupAfterIntersectionTest(geometry_under_test *pGTest)
{
if (!pGTest->pUsedNodesMap)
return;
if ((unsigned int)(pGTest->pUsedNodesMap-g_UsedNodesMap) > (unsigned int)sizeof(g_UsedNodesMap)/sizeof(g_UsedNodesMap[0])) {
delete[] pGTest->pUsedNodesMap; return;
}
if (pGTest->nUsedNodes < pGTest->nMaxUsedNodes-1) {
for(int i=0;i<=pGTest->nUsedNodes;i++)
pGTest->pUsedNodesMap[pGTest->pUsedNodesIdx[i]>>5] &= ~(1<<(pGTest->pUsedNodesIdx[i]&31));
} else
memset(pGTest->pUsedNodesMap, 0, ((m_nNodes-1>>5)+1)*4);
}
void COBBTree::GetMemoryStatistics(ICrySizer *pSizer)
{
SIZER_COMPONENT_NAME(pSizer, "OBB trees");
pSizer->AddObject(this, sizeof(COBBTree));
pSizer->AddObject(m_pNodes, m_nNodesAlloc*sizeof(m_pNodes[0]));
if (m_pTri2Node)
pSizer->AddObject(m_pTri2Node, m_pMesh->m_nTris*sizeof(m_pTri2Node[0]));
}
void COBBTree::Save(CMemStream &stm)
{
stm.Write(m_nNodes);
stm.Write(m_pNodes, m_nNodes*sizeof(m_pNodes[0]));
stm.Write(m_nMaxTrisInNode);
stm.Write(m_nMinTrisPerNode);
stm.Write(m_nMaxTrisPerNode);
stm.Write(m_maxSkipDim);
}
void COBBTree::Load(CMemStream &stm, CGeometry *pGeom)
{
m_pMesh = (CTriMesh*)pGeom;
stm.Read(m_nNodes);
m_pNodes = new OBBnode[m_nNodesAlloc=m_nNodes];
stm.Read(m_pNodes, m_nNodes*sizeof(m_pNodes[0]));
m_pTri2Node = new index_t[m_pMesh->m_nTris];
for(int i=0;i<m_nNodes;i++) for(int j=0;j<m_pNodes[i].ntris;j++)
m_pTri2Node[m_pNodes[i].ichild+j] = i;
stm.Read(m_nMaxTrisInNode);
stm.Read(m_nMinTrisPerNode);
stm.Read(m_nMaxTrisPerNode);
stm.Read(m_maxSkipDim);
}

68
CryPhysics/obbtree.h Normal file
View File

@@ -0,0 +1,68 @@
#ifndef obbtree_h
#define obbtree_h
#pragma once
struct OBBnode {
vectorf axes[3];
vectorf center;
vectorf size;
int iparent;
int ichild;
int ntris;
};
class CTriMesh;
class COBBTree : public CBVTree {
public:
COBBTree() { m_nMinTrisPerNode=2; m_nMaxTrisPerNode=4; m_maxSkipDim=0; m_pNodes=0; m_pTri2Node=0; }
virtual ~COBBTree() {
if (m_pNodes) delete[] m_pNodes; m_pNodes=0;
if (m_pTri2Node) delete[] m_pTri2Node; m_pTri2Node=0;
}
virtual int GetType() { return BVT_OBB; }
virtual float Build(CGeometry *pMesh);
virtual void SetGeomConvex();
void SetParams(int nMinTrisPerNode,int nMaxTrisPerNode, float skipdim);
float BuildNode(int iNode, int iTriStart,int nTris, int nDepth);
virtual int PrepareForIntersectionTest(geometry_under_test *pGTest);
virtual void CleanupAfterIntersectionTest(geometry_under_test *pGTest);
virtual void GetBBox(box *pbox);
virtual int MaxPrimsInNode() { return m_nMaxTrisInNode; }
virtual void GetNodeBV(BV *&pBV, int iNode=0);
virtual void GetNodeBV(BV *&pBV, const vectorf &sweepdir,float sweepstep, int iNode=0);
virtual void GetNodeBV(const matrix3x3f &Rw,const vectorf &offsw,float scalew, BV *&pBV, int iNode=0);
virtual void GetNodeBV(const matrix3x3f &Rw,const vectorf &offsw,float scalew, BV *&pBV, const vectorf &sweepdir,float sweepstep, int iNode=0) {}
virtual float SplitPriority(const BV* pBV);
virtual void GetNodeChildrenBVs(const matrix3x3f &Rw,const vectorf &offsw,float scalew, const BV *pBV_parent, BV *&pBV_child1,BV *&pBV_child2);
virtual void GetNodeChildrenBVs(const BV *pBV_parent, BV *&pBV_child1,BV *&pBV_child2);
virtual void GetNodeChildrenBVs(const BV *pBV_parent, const vectorf &sweepdir,float sweepstep, BV *&pBV_child1,BV *&pBV_child2);
virtual void ReleaseLastBVs();
virtual void ReleaseLastSweptBVs();
virtual int GetNodeContents(int iNode, BV *pBVCollider,int bColliderUsed,int bColliderLocal,
geometry_under_test *pGTest,geometry_under_test *pGTestOp);
virtual int GetNodeContentsIdx(int iNode, int &iStartPrim) { iStartPrim = m_pNodes[iNode].ichild; return m_pNodes[iNode].ntris; }
virtual void MarkUsedTriangle(int itri, geometry_under_test *pGTest);
virtual void GetMemoryStatistics(ICrySizer *pSizer);
virtual void Save(CMemStream &stm);
virtual void Load(CMemStream &stm, CGeometry *pGeom);
CTriMesh *m_pMesh;
OBBnode *m_pNodes;
int m_nNodes;
int m_nNodesAlloc;
index_t *m_pTri2Node;
int m_nMaxTrisInNode;
int m_nMinTrisPerNode;
int m_nMaxTrisPerNode;
float m_maxSkipDim;
int *m_pMapVtxUsed;
vectorf *m_pVtxUsed;
};
#endif

View File

@@ -0,0 +1,430 @@
#include "stdafx.h"
#include "utils.h"
#include "primitives.h"
#include "overlapchecks.h"
COverlapChecker g_Overlapper;
COverlapChecker::COverlapChecker()
{
for(int i=0;i<NPRIMS;i++) for(int j=0;j<NPRIMS;j++)
table[i][j] = default_overlap_check;
table[box::type][box::type] = (overlap_check)box_box_overlap_check;
table[box::type][triangle::type] = (overlap_check)box_tri_overlap_check;
table[triangle::type][box::type] = (overlap_check)tri_box_overlap_check;
table[box::type][heightfield::type] = (overlap_check)box_heightfield_overlap_check;
table[heightfield::type][box::type] = (overlap_check)heightfield_box_overlap_check;
table[box::type][ray::type] = (overlap_check)box_ray_overlap_check;
table[ray::type][box::type] = (overlap_check)ray_box_overlap_check;
table[box::type][sphere::type] = (overlap_check)box_sphere_overlap_check;
table[sphere::type][box::type] = (overlap_check)sphere_box_overlap_check;
table[triangle::type][sphere::type] = (overlap_check)tri_sphere_overlap_check;
table[sphere::type][triangle::type] = (overlap_check)sphere_tri_overlap_check;
table[sphere::type][sphere::type] = (overlap_check)sphere_sphere_overlap_check;
table[heightfield::type][sphere::type] = (overlap_check)heightfield_sphere_overlap_check;
table[sphere::type][heightfield::type] = (overlap_check)sphere_heightfield_overlap_check;
}
int default_overlap_check(const primitive*, const primitive *)
{
return 1;
}
int box_box_overlap_check(const box *box1, const box *box2)
{
int i;
matrix3x3RMf &Basis21((matrix3x3RMf&)*(matrix3x3RMf*)g_Overlapper.Basis21);
if ((box1->bOriented|box2->bOriented<<16)!=g_Overlapper.iPrevCode) {
if (!box1->bOriented)
Basis21 = box2->Basis.T();
else if (box2->bOriented)
Basis21 = box1->Basis*box2->Basis.T();
else
Basis21 = box1->Basis;
for(i=0;i<9;i++)
g_Overlapper.Basis21abs[i] = fabsf(g_Overlapper.Basis21[i]);
g_Overlapper.iPrevCode = box1->bOriented|box2->bOriented<<16;
}
vectorf center21 = box2->center-box1->center;
if (box1->bOriented)
center21 = box1->Basis*center21;
const vectorf &a=box1->size, &b=box2->size;
float t1,t2,t3,e=(a.x+a.y+a.z)*1e-4f;
// node1 basis vectors
if (fabsf(center21.x) > a.x+b*vectorf(g_Overlapper.Basis21abs+0))
return 0;
if (fabsf(center21.y) > a.y+b*vectorf(g_Overlapper.Basis21abs+3))
return 0;
if (fabsf(center21.z) > a.z+b*vectorf(g_Overlapper.Basis21abs+6))
return 0;
// node2 basis vectors
if (fabsf(center21.x*g_Overlapper.Basis21[0]+center21.y*g_Overlapper.Basis21[3]+center21.z*g_Overlapper.Basis21[6]) >
a.x*g_Overlapper.Basis21abs[0]+a.y*g_Overlapper.Basis21abs[3]+a.z*g_Overlapper.Basis21abs[6]+b.x)
return 0;
if (fabsf(center21.x*g_Overlapper.Basis21[1]+center21.y*g_Overlapper.Basis21[4]+center21.z*g_Overlapper.Basis21[7]) >
a.x*g_Overlapper.Basis21abs[1]+a.y*g_Overlapper.Basis21abs[4]+a.z*g_Overlapper.Basis21abs[7]+b.y)
return 0;
if (fabsf(center21.x*g_Overlapper.Basis21[2]+center21.y*g_Overlapper.Basis21[5]+center21.z*g_Overlapper.Basis21[8]) >
a.x*g_Overlapper.Basis21abs[2]+a.y*g_Overlapper.Basis21abs[5]+a.z*g_Overlapper.Basis21abs[8]+b.z)
return 0;
// node1->axes[0] x node2->axes[0]
t1 = a.y*g_Overlapper.Basis21abs[6] + a.z*g_Overlapper.Basis21abs[3];
t2 = b.y*g_Overlapper.Basis21abs[2] + b.z*g_Overlapper.Basis21abs[1];
t3 = center21.z*g_Overlapper.Basis21[3] - center21.y*g_Overlapper.Basis21[6];
if (fabsf(t3) > t1+t2+e)
return 0;
// node1->axes[0] x node2->axes[1]
t1 = a.y*g_Overlapper.Basis21abs[7] + a.z*g_Overlapper.Basis21abs[4];
t2 = b.x*g_Overlapper.Basis21abs[2] + b.z*g_Overlapper.Basis21abs[0];
t3 = center21.z*g_Overlapper.Basis21[4] - center21.y*g_Overlapper.Basis21[7];;
if(fabsf(t3) > t1+t2+e)
return 0;
// node1->axes[0] x node2->axes[2]
t1 = a.y*g_Overlapper.Basis21abs[8] + a.z*g_Overlapper.Basis21abs[5];
t2 = b.x*g_Overlapper.Basis21abs[1] + b.y*g_Overlapper.Basis21abs[0];
t3 = center21.z*g_Overlapper.Basis21[5] - center21.y*g_Overlapper.Basis21[8];
if(fabsf(t3) > t1+t2+e)
return 0;
// node1->axes[1] x node2->axes[0]
t1 = a.x*g_Overlapper.Basis21abs[6] + a.z*g_Overlapper.Basis21abs[0];
t2 = b.y*g_Overlapper.Basis21abs[5] + b.z*g_Overlapper.Basis21abs[4];
t3 = center21.x*g_Overlapper.Basis21[6] - center21.z*g_Overlapper.Basis21[0];
if(fabsf(t3) > t1+t2+e)
return 0;
// node1->axes[1] x node2->axes[1]
t1 = a.x*g_Overlapper.Basis21abs[7] + a.z*g_Overlapper.Basis21abs[1];
t2 = b.x*g_Overlapper.Basis21abs[5] + b.z*g_Overlapper.Basis21abs[3];
t3 = center21.x*g_Overlapper.Basis21[7] - center21.z*g_Overlapper.Basis21[1];
if(fabsf(t3) > t1+t2+e)
return 0;
// node1->axes[1] x node2->axes[2]
t1 = a.x*g_Overlapper.Basis21abs[8] + a.z*g_Overlapper.Basis21abs[2];
t2 = b.x*g_Overlapper.Basis21abs[4] + b.y*g_Overlapper.Basis21abs[3];
t3 = center21.x*g_Overlapper.Basis21[8] - center21.z*g_Overlapper.Basis21[2];
if(fabsf(t3) > t1+t2+e)
return 0;
// node1->axes[2] x node2->axes[0]
t1 = a.x*g_Overlapper.Basis21abs[3] + a.y*g_Overlapper.Basis21abs[0];
t2 = b.y*g_Overlapper.Basis21abs[8] + b.z*g_Overlapper.Basis21abs[7];
t3 = center21.y*g_Overlapper.Basis21[0] - center21.x*g_Overlapper.Basis21[3];
if(fabsf(t3) > t1+t2+e)
return 0;
// node1->axes[2] x node2->axes[1]
t1 = a.x*g_Overlapper.Basis21abs[4] + a.y*g_Overlapper.Basis21abs[1];
t2 = b.x*g_Overlapper.Basis21abs[8] + b.z*g_Overlapper.Basis21abs[6];
t3 = center21.y*g_Overlapper.Basis21[1] - center21.x*g_Overlapper.Basis21[4];
if(fabsf(t3) > t1+t2+e)
return 0;
// node1->axes[2] x node2->axes[2]
t1 = a.x*g_Overlapper.Basis21abs[5] + a.y*g_Overlapper.Basis21abs[2];
t2 = b.x*g_Overlapper.Basis21abs[7] + b.y*g_Overlapper.Basis21abs[6];
t3 = center21.y*g_Overlapper.Basis21[2] - center21.x*g_Overlapper.Basis21[5];
if(fabsf(t3) > t1+t2+e)
return 0;
return 1;
}
int box_heightfield_overlap_check(const box *pbox, const heightfield *phf)
{
box boxtr;
vectorf vtx[4];
triangle hftri;
vector2df sz,ptmin,ptmax;
int ix,iy,ix0,iy0,ix1,iy1,icell;
float hmax;
// find the 3 lowest vertices
if (phf->bOriented) {
if (pbox->bOriented)
boxtr.Basis = pbox->Basis*phf->Basis.T();
else
boxtr.Basis = phf->Basis.T();
boxtr.center = phf->Basis*(pbox->center-phf->origin);
} else {
boxtr.Basis = pbox->Basis;
boxtr.center = pbox->center-phf->origin;
}
boxtr.bOriented = 1;
boxtr.Basis.SetRow(0,boxtr.Basis.GetRow(0)*-sgnnz(boxtr.Basis(0,2)));
boxtr.Basis.SetRow(1,boxtr.Basis.GetRow(1)*-sgnnz(boxtr.Basis(1,2)));
boxtr.Basis.SetRow(2,boxtr.Basis.GetRow(2)*-sgnnz(boxtr.Basis(2,2)));
boxtr.size = pbox->size;
vtx[0] = pbox->size*boxtr.Basis;
boxtr.Basis.SetRow(0,-boxtr.Basis.GetRow(0)); vtx[1]=pbox->size*boxtr.Basis; boxtr.Basis.SetRow(0,-boxtr.Basis.GetRow(0));
boxtr.Basis.SetRow(1,-boxtr.Basis.GetRow(1)); vtx[2]=pbox->size*boxtr.Basis; boxtr.Basis.SetRow(1,-boxtr.Basis.GetRow(1));
boxtr.Basis.SetRow(2,-boxtr.Basis.GetRow(2)); vtx[3]=pbox->size*boxtr.Basis; boxtr.Basis.SetRow(2,-boxtr.Basis.GetRow(2));
// find the underlying grid rectangle
sz.x = sz.y = 0;
sz.x = max(sz.x, fabsf(vtx[1].x)); sz.y = max(sz.y, fabsf(vtx[1].y));
sz.x = max(sz.x, fabsf(vtx[2].x)); sz.y = max(sz.y, fabsf(vtx[2].y));
sz.x = max(sz.x, fabsf(vtx[3].x)); sz.y = max(sz.y, fabsf(vtx[3].y));
ptmin.x = (boxtr.center.x-sz.x)*phf->stepr.x; ptmin.y = (boxtr.center.y-sz.y)*phf->stepr.y;
ptmax.x = (boxtr.center.x+sz.x)*phf->stepr.x; ptmax.y = (boxtr.center.y+sz.y)*phf->stepr.y;
ix0 = float2int(ptmin.x-0.5f); iy0 = float2int(ptmin.y-0.5f); ix0 &= ~(ix0>>31); iy0 &= ~(iy0>>31);
ix1 = min(float2int(ptmax.x+0.5f),phf->size.x); iy1 = min(float2int(ptmax.y+0.5f),phf->size.y);
//if (ix0>ix1 || iy0>iy1 || phf->gettype(ix0,iy0)==-1) // now checks are in CTriMesh on per-tri basis, using materials
// return 0;
vtx[0]+=boxtr.center; vtx[1]+=boxtr.center; vtx[2]+=boxtr.center; vtx[3]+=boxtr.center;
// check if all heightfield points are below the lowest box point
for(ix=ix0,hmax=0;ix<=ix1;ix++) for(iy=iy0;iy<=iy1;iy++)
hmax = max(hmax,phf->getheight(ix,iy));
if (hmax<vtx[0].z)
return 0;
if ((ix1-ix0)*(iy1-iy0)<=4) {
// check for intersection with each underlying triangle
for(ix=ix0;ix<ix1;ix++) for(iy=iy0;iy<iy1;iy++) {
icell = ix*phf->stride.x+iy*phf->stride.y;
hftri.pt[0].x=hftri.pt[2].x = ix*phf->step.x; hftri.pt[0].y=hftri.pt[1].y = iy*phf->step.y;
hftri.pt[1].x = hftri.pt[0].x+phf->step.x; hftri.pt[2].y = hftri.pt[0].y+phf->step.y;
hftri.pt[0].z = phf->getheight(icell); hftri.pt[1].z = phf->getheight(icell+phf->stride.x);
hftri.pt[2].z = phf->getheight(icell+phf->stride.y);
hftri.n = hftri.pt[1]-hftri.pt[0] ^ hftri.pt[2]-hftri.pt[0];
if (box_tri_overlap_check(&boxtr,&hftri))
return 1;
hftri.pt[0] = hftri.pt[2]; hftri.pt[2].x += phf->step.x; hftri.pt[2].z = phf->getheight(icell+phf->stride.x+phf->stride.y);
hftri.n = hftri.pt[1]-hftri.pt[0] ^ hftri.pt[2]-hftri.pt[0];
if (box_tri_overlap_check(&boxtr,&hftri))
return 1;
}
return 0;
}
return 1;
}
int heightfield_box_overlap_check(const heightfield *phf, const box *pbox)
{
return box_heightfield_overlap_check(pbox,phf);
}
int box_tri_overlap_check(const box *pbox, const triangle *ptri)
{
vectorf pt[3],n;
float l1,l2,l3,l,c;
if (pbox->bOriented) {
pt[0] = pbox->Basis*(ptri->pt[0]-pbox->center);
pt[1] = pbox->Basis*(ptri->pt[1]-pbox->center);
pt[2] = pbox->Basis*(ptri->pt[2]-pbox->center);
n = pbox->Basis*ptri->n;
} else {
pt[0] = ptri->pt[0]-pbox->center;
pt[1] = ptri->pt[1]-pbox->center;
pt[2] = ptri->pt[2]-pbox->center;
n = ptri->n;
}
// check box normals
l1=fabsf(pt[0].x-pt[1].x); l2=fabsf(pt[1].x-pt[2].x); l3=fabsf(pt[2].x-pt[0].x); l=l1+l2+l3; // half length = l/4
c = (l1*(pt[0].x+pt[1].x)+l2*(pt[1].x+pt[2].x)+l3*(pt[2].x+pt[0].x))*0.5f; // center = c/l
if (fabsf(c) > (pbox->size.x+l*0.25f)*l)
return 0;
l1=fabsf(pt[0].y-pt[1].y); l2=fabsf(pt[1].y-pt[2].y); l3=fabsf(pt[2].y-pt[0].y); l=l1+l2+l3;
c = (l1*(pt[0].y+pt[1].y)+l2*(pt[1].y+pt[2].y)+l3*(pt[2].y+pt[0].y))*0.5f;
if (fabsf(c) > (pbox->size.y+l*0.25f)*l)
return 0;
l1=fabsf(pt[0].z-pt[1].z); l2=fabsf(pt[1].z-pt[2].z); l3=fabsf(pt[2].z-pt[0].z); l=l1+l2+l3;
c = (l1*(pt[0].z+pt[1].z)+l2*(pt[1].z+pt[2].z)+l3*(pt[2].z+pt[0].z))*0.5f;
if (fabsf(c) > (pbox->size.z+l*0.25f)*l)
return 0;
// check triangle normal
if (fabsf(n.x)*pbox->size.x+fabsf(n.y)*pbox->size.y+fabsf(n.z)*pbox->size.z < fabsf(n*pt[0]))
return 0;
vectorf edge,triproj1,triproj2;
float boxproj;
// check triangle edges - box edges cross products
for(int i=0;i<3;i++) {
edge = pt[inc_mod3[i]]-pt[i]; triproj1 = edge^pt[i]; triproj2 = edge^pt[dec_mod3[i]];
boxproj = fabsf(pbox->size.y*edge.z) + fabsf(pbox->size.z*edge.y);
if (fabsf((triproj1.x+triproj2.x)*0.5f) > boxproj+fabsf(triproj1.x-triproj2.x)*0.5f)
return 0;
boxproj = fabsf(pbox->size.x*edge.z) + fabsf(pbox->size.z*edge.x);
if (fabsf((triproj1.y+triproj2.y)*0.5f) > boxproj+fabsf(triproj1.y-triproj2.y)*0.5f)
return 0;
boxproj = fabsf(pbox->size.x*edge.y) + fabsf(pbox->size.y*edge.x);
if (fabsf((triproj1.z+triproj2.z)*0.5f) > boxproj+fabsf(triproj1.z-triproj2.z)*0.5f)
return 0;
}
return 1;
}
int tri_box_overlap_check(const triangle *ptri, const box *pbox)
{
return box_tri_overlap_check(pbox,ptri);
}
int box_ray_overlap_check(const box *pbox, const ray *pray)
{
vectorf l,m,al;
if (pbox->bOriented) {
l = pbox->Basis*pray->dir*0.5f;
m = pbox->Basis*(pray->origin-pbox->center)+l;
} else {
l = pray->dir*0.5f;
m = pray->origin+l-pbox->center;
}
al.x=fabsf(l.x); al.y=fabsf(l.y); al.z=fabsf(l.z);
// separating axis check for line and box
if (fabsf(m.x) > pbox->size.x+al.x)
return 0;
if (fabsf(m.y) > pbox->size.y+al.y)
return 0;
if (fabsf(m.z) > pbox->size.z+al.z)
return 0;
if (fabsf(m.z*l.y-m.y*l.z) > pbox->size.y*al.z+pbox->size.z*al.y)
return 0;
if (fabsf(m.x*l.z-m.z*l.x) > pbox->size.x*al.z+pbox->size.z*al.x)
return 0;
if (fabsf(m.x*l.y-m.y*l.x) > pbox->size.x*al.y+pbox->size.y*al.x)
return 0;
return 1;
}
int ray_box_overlap_check(const ray *pray, const box *pbox)
{
return box_ray_overlap_check(pbox,pray);
}
int box_sphere_overlap_check(const box *pbox, const sphere *psph)
{
vectorf center=psph->center-pbox->center, dist;
if (pbox->bOriented)
center = pbox->Basis*center;
dist.x = max(0.0f, fabsf(center.x)-pbox->size.x);
dist.y = max(0.0f, fabsf(center.y)-pbox->size.y);
dist.z = max(0.0f, fabsf(center.z)-pbox->size.z);
return isneg(dist.len2()-sqr(psph->r));
}
int sphere_box_overlap_check(const sphere *psph, const box *pbox)
{
return box_sphere_overlap_check(pbox,psph);
}
quotientf tri_sphere_dist2(const triangle* ptri, const sphere* psph, int& bFace)
{
int i,bInside[2];
float rvtx[3],elen2[2],denom;
vectorf edge[2],dp;
bFace = 0;
rvtx[0] = (ptri->pt[0]-psph->center).len2();
rvtx[1] = (ptri->pt[1]-psph->center).len2();
rvtx[2] = (ptri->pt[2]-psph->center).len2();
i = idxmin3(rvtx);
dp = psph->center-ptri->pt[i];
edge[0] = ptri->pt[inc_mod3[i]]-ptri->pt[i]; elen2[0] = edge[0].len2();
edge[1] = ptri->pt[dec_mod3[i]]-ptri->pt[i]; elen2[1] = edge[1].len2();
bInside[0] = isneg((dp^edge[0])*ptri->n);
bInside[1] = isneg((edge[1]^dp)*ptri->n);
rvtx[i] = rvtx[i]*elen2[bInside[0]] - sqr(max(0.0f,dp*edge[bInside[0]]))*(bInside[0]|bInside[1]);
denom = elen2[bInside[0]];
if (bInside[0]&bInside[1]) {
if (edge[0]*edge[1]<0) {
edge[0] = ptri->pt[dec_mod3[i]]-ptri->pt[inc_mod3[i]];
dp = psph->center-ptri->pt[inc_mod3[i]];
if ((dp^edge[0])*ptri->n>0)
return quotientf(rvtx[inc_mod3[i]]*edge[0].len2()-sqr(dp*edge[0]), edge[0].len2());
}
bFace = 1;
return quotientf(sqr((psph->center-ptri->pt[0])*ptri->n),1.0f);
}
return quotientf(rvtx[i],denom);
}
int tri_sphere_overlap_check(const triangle *ptri, const sphere *psph)
{
int bFace;
return isneg(tri_sphere_dist2(ptri,psph,bFace)-sqr(psph->r));
/*float r2=sqr(psph->r),edgelen2;
vectorf edge,dp0,dp1;
if ((ptri->pt[0]-psph->center).len2()<r2)
return 1;
if ((ptri->pt[1]-psph->center).len2()<r2)
return 1;
if ((ptri->pt[2]-psph->center).len2()<r2)
return 1;
edgelen2 = (edge = ptri->pt[1]-ptri->pt[0]).len2(); dp0 = ptri->pt[0]-psph->center; dp1 = ptri->pt[1]-psph->center;
if (isneg((dp0^edge).len2()-r2*edgelen2) & isneg((dp0*edge)*(dp1*edge)))
return 1;
edgelen2 = (edge = ptri->pt[2]-ptri->pt[1]).len2(); dp0 = ptri->pt[1]-psph->center; dp1 = ptri->pt[2]-psph->center;
if (isneg((dp0^edge).len2()-r2*edgelen2) & isneg((dp0*edge)*(dp1*edge)))
return 1;
edgelen2 = (edge = ptri->pt[0]-ptri->pt[2]).len2(); dp0 = ptri->pt[2]-psph->center; dp1 = ptri->pt[0]-psph->center;
if (isneg((dp0^edge).len2()-r2*edgelen2) & isneg((dp0*edge)*(dp1*edge)))
return 1;
return 0;*/
}
int sphere_tri_overlap_check(const sphere *psph, const triangle *ptri)
{
return tri_sphere_overlap_check(ptri,psph);
}
int sphere_sphere_overlap_check(const sphere *psph1, const sphere *psph2)
{
return isneg((psph1->center-psph2->center).len2()-sqr(psph1->r+psph2->r));
}
int heightfield_sphere_overlap_check(const heightfield *phf, const sphere *psph)
{
vectorf center;
vector2di irect[2];
int ix,iy,bContact=0;
center = phf->Basis*(psph->center-phf->origin);
irect[0].x = min(phf->size.x,max(0,float2int((center.x-psph->r)*phf->stepr.x-0.5f)));
irect[0].y = min(phf->size.y,max(0,float2int((center.y-psph->r)*phf->stepr.y-0.5f)));
irect[1].x = min(phf->size.x,max(0,float2int((center.x+psph->r)*phf->stepr.x+0.5f)));
irect[1].y = min(phf->size.y,max(0,float2int((center.y+psph->r)*phf->stepr.y+0.5f)));
for(ix=irect[0].x;ix<irect[1].x;ix++) for(iy=irect[0].y;iy<irect[1].y;iy++)
bContact |= isneg(center.z-psph->r-phf->getheight(ix,iy));
return bContact;
}
int sphere_heightfield_overlap_check(const sphere *psph, const heightfield *phf)
{
return heightfield_sphere_overlap_check(phf,psph);
}

View File

@@ -0,0 +1,42 @@
#ifndef overlapchecks_h
#define overlapchecks_h
typedef int (*overlap_check)(const primitive*,const primitive*);
int default_overlap_check(const primitive*, const primitive*);
int box_box_overlap_check(const box *box1, const box *box2);
int box_heightfield_overlap_check(const box *pbox, const heightfield *phf);
int heightfield_box_overlap_check(const heightfield *phf, const box *pbox);
int box_tri_overlap_check(const box *pbox, const triangle *ptri);
int tri_box_overlap_check(const triangle *ptri, const box *pbox);
int box_ray_overlap_check(const box *pbox, const ray *pray);
int ray_box_overlap_check(const ray *pray, const box *pbox);
int box_sphere_overlap_check(const box *pbox, const sphere *psph);
int sphere_box_overlap_check(const sphere *psph, const box *pbox);
int tri_sphere_overlap_check(const triangle *ptri, const sphere *psph);
int sphere_tri_overlap_check(const sphere *psph, const triangle *ptri);
int heightfield_sphere_overlap_check(const heightfield *phf, const sphere *psph);
int sphere_heightfield_overlap_check(const sphere *psph, const heightfield *phf);
int sphere_sphere_overlap_check(const sphere *psph1, const sphere *psph2);
quotientf tri_sphere_dist2(const triangle *ptri, const sphere *psph, int &bFace);
class COverlapChecker {
public:
COverlapChecker();
void Init() { iPrevCode = -1; }
int Check(int type1,int type2, primitive *prim1,primitive *prim2) {
return table[type1][type2](prim1,prim2);
}
int CheckExists(int type1,int type2) {
return table[type1][type2]!=default_overlap_check;
}
overlap_check table[NPRIMS][NPRIMS];
int iPrevCode;
float Basis21[9];
float Basis21abs[9];
};
extern COverlapChecker g_Overlapper;
#endif

View File

@@ -0,0 +1,695 @@
//////////////////////////////////////////////////////////////////////
//
// Particle Entity
//
// File: particleentity.cpp
// Description : CParticleEntity class implementation
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "bvtree.h"
#include "geometry.h"
#include "singleboxtree.h"
#include "raybv.h"
#include "raygeom.h"
#include "intersectionchecks.h"
#include "rigidbody.h"
#include "physicalplaceholder.h"
#include "physicalentity.h"
#include "geoman.h"
#include "physicalworld.h"
#include "particleentity.h"
CParticleEntity::CParticleEntity(CPhysicalWorld *pWorld) : CPhysicalEntity(pWorld)
{
m_gravity = pWorld->m_vars.gravity; m_mass=0.2f; m_dim=m_dimLying=0.05f; m_rdim=20.0f;
m_heading.Set(1,0,0); m_vel.zero(); m_wspin.zero();
m_waterGravity = m_gravity*0.8f;
m_kAirResistance = 0;
m_kWaterResistance = 0.5f;
m_accThrust = 0;
m_kAccLift = 0;
m_qspin.SetIdentity();
m_surface_idx = 0;
m_dirdown.Set(0,0,-1);
m_normal.Set(0,0,1);
m_flags = 0;
m_iSimClass = 4;
for(int i=0;i<sizeof(m_CollHistory)/sizeof(m_CollHistory[0]);i++)
m_CollHistory[i].age = 1E10;
m_iCollHistory = 0;
m_bSliding = 0;
m_slide_normal.Set(0,0,1);
m_minBounceVel = 1.5f;
m_pColliderToIgnore = 0;
m_iPierceability = sf_max_pierceable;
m_ig[0].x=m_ig[1].x=m_ig[0].y=m_ig[1].y = -3;
m_timeSurplus = 0;
m_defpart.flags = 0;
m_defpart.id = 0;
m_defpart.pos.zero();
m_defpart.q.SetIdentity();
m_defpart.scale = 1.0f;
m_defpart.mass = 0;
m_defpart.minContactDist = 0;
m_waterPlane.origin.zero();
m_waterPlane.n.Set(0,0,1);
m_waterDensity = 1000.0f;
m_bForceAwake = -1;
m_timeForceAwake = 0;
m_sleepTime = 0;
}
CParticleEntity::~CParticleEntity()
{
if (m_nParts>0 && m_pWorld)
m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[0].pPhysGeom);
m_nParts = 0;
}
int CParticleEntity::SetParams(pe_params *_params)
{
int res;
if (res = CPhysicalEntity::SetParams(_params)) {
if (_params->type==pe_params_flags::type_id) {
pe_params_particle pp;
SetParams(&pp);
}
return res;
}
if (_params->type==pe_params_particle::type_id) {
pe_params_particle *params = (pe_params_particle*)_params;
ENTITY_VALIDATE("CParticleEntity:SetParams(pe_params_particle)",params);
if (!is_unused(params->mass)) m_mass = params->mass;
if (!is_unused(params->size)) {
m_rdim = 1.0f/(m_dim = params->size*0.5f);
m_dimLying = params->size*0.5f;
}
if (!is_unused(params->thickness)) m_dimLying = params->thickness*0.5f;
if (!is_unused(params->kAirResistance)) m_kAirResistance = params->kAirResistance;
if (!is_unused(params->kWaterResistance)) m_kWaterResistance = params->kWaterResistance;
if (!is_unused(params->accThrust)) m_accThrust = params->accThrust;
if (!is_unused(params->accLift) && !is_unused(params->velocity))
m_kAccLift = params->velocity!=0 ? params->accLift/fabs_tpl(params->velocity):0;
if (!is_unused(params->heading)) m_heading = params->heading;
if (!is_unused(params->velocity)) m_vel = m_heading*params->velocity;
if (!is_unused(params->wspin)) m_wspin = params->wspin;
if (!is_unused(params->gravity)) {
m_gravity = params->gravity;
if (m_gravity.len2()>0)
(m_dirdown=m_gravity).normalize();
else m_dirdown.Set(0,0,-1);
}
if (!is_unused(params->waterGravity)) m_waterGravity = params->waterGravity;
if (!is_unused(params->normal)) m_normal = params->normal;
if (!is_unused(params->q0)) m_qspin = params->q0;
if (!is_unused(params->minBounceVel)) m_minBounceVel = params->minBounceVel;
if (!is_unused(params->surface_idx)) m_surface_idx = params->surface_idx;
if (!is_unused(params->flags)) m_flags = params->flags;
if (m_flags & particle_traceable) {
if (m_ig[0].x==-3)
m_ig[0].x=m_ig[1].x=m_ig[0].y=m_ig[1].y = -2;
if (m_pos.len2()>0)
m_pWorld->RepositionEntity(this,1);
} else {
if (m_ig[0].x!=-3) {
m_pWorld->DetachEntityGridThunks(this);
m_ig[0].x=m_ig[1].x=m_ig[0].y=m_ig[1].y = -3;
}
}
if (!is_unused(params->pColliderToIgnore))
m_pColliderToIgnore = (CPhysicalEntity*)params->pColliderToIgnore;
if (!is_unused(params->iPierceability))
m_iPierceability = params->iPierceability;
if (!(m_flags & particle_constant_orientation)) {
if (!(m_flags & particle_no_path_alignment)) {
vectorf dirbuf[3];
dirbuf[0] = m_dirdown^m_heading; dirbuf[1] = m_heading;
// if (dirbuf[0].len2()<0.01f) dirbuf[0] = m_heading.orthogonal();
if (dirbuf[0].len2()<0.01f) dirbuf[0].SetOrthogonal(m_heading);
dirbuf[0].normalize(); dirbuf[2] = dirbuf[0]^dirbuf[1];
m_qrot = quaternionf((matrix3x3CMf&)dirbuf[0])*m_qspin;
} else
m_qrot = m_qspin;
}
m_BBox[0] = m_pos-vectorf(m_dim,m_dim,m_dim);
m_BBox[1] = m_pos+vectorf(m_dim,m_dim,m_dim);
return 1;
}
if (_params->type==pe_params_buoyancy::type_id) {
pe_params_buoyancy *params = (pe_params_buoyancy*)_params;
if (!is_unused(params->waterDensity)) m_waterDensity = params->waterDensity;
if (!is_unused(params->waterPlane.n)) m_waterPlane.n = params->waterPlane.n;
if (!is_unused(params->waterPlane.origin)) m_waterPlane.origin = params->waterPlane.origin;
return 1;
}
return 0;
}
int CParticleEntity::GetParams(pe_params *_params)
{
if (CPhysicalEntity::GetParams(_params))
return 1;
if (_params->type==pe_params_particle::type_id) {
pe_params_particle *params = (pe_params_particle*)_params;
params->mass = m_mass;
params->size = m_dim*2.0f;
params->thickness = m_dimLying*2.0f;
params->heading = m_heading;
params->velocity = m_vel.len();
params->wspin = m_wspin;
params->gravity = m_gravity;
params->normal = m_normal;
params->kAirResistance = m_kAirResistance;
params->accThrust = m_accThrust;
params->accLift = params->velocity*m_kAccLift;
params->q0 = m_qspin;
params->surface_idx = m_surface_idx;
params->flags = m_flags;
params->pColliderToIgnore = m_pColliderToIgnore;
params->iPierceability = m_iPierceability;
return 1;
}
if (_params->type==pe_params_buoyancy::type_id) {
pe_params_buoyancy *params = (pe_params_buoyancy*)_params;
params->waterDensity = m_waterDensity;
params->waterDamping = 0;
params->waterPlane = m_waterPlane;
params->waterFlow.zero();
params->waterResistance = 0;
params->waterEmin = 0;
return 1;
}
return 0;
}
int CParticleEntity::GetStateSnapshot(CStream &stm, float time_back, int flags)
{
stm.WriteNumberInBits(SNAPSHOT_VERSION, 4);
if (m_pWorld->m_vars.bMultiplayer) {
if (!IsAwake()) {
if (m_sleepTime>5.0f)
stm.Write(false);
else {
stm.Write(true);
stm.Write(m_pos);
stm.Write(false);
}
} else {
stm.Write(true); stm.Write(m_pos);
stm.Write(true);
stm.Write(m_vel);
if (!m_bSliding) stm.Write(false);
else {
stm.Write(true);
stm.Write(asin_tpl(m_slide_normal.z));
stm.Write(atan2_tpl(m_slide_normal.y,m_slide_normal.x));
}
}
} else {
stm.Write(m_pos);
stm.Write(m_vel);
if (!m_bSliding) stm.Write(false);
else {
stm.Write(true);
stm.Write(asin_tpl(m_slide_normal.z));
stm.Write(atan2_tpl(m_slide_normal.y,m_slide_normal.x));
}
}
/*if (m_qspin.v.len2()<0.01*0.01) stm.Write(false);
else {
stm.Write(true);
//CHANGED_BY_IVO (NOTE: order of angles is flipped!!!!)
//float angles[3]; m_qspin.get_Euler_angles_xyz(angles[0],angles[1],angles[2]);
//EULER_IVO
//Vec3 TempAng; m_qspin.GetEulerAngles_XYZ( TempAng );
vectorf angles = Ang3::GetAnglesXYZ(matrix3x3f(m_qspin));
for(int i=0;i<3;i++) stm.Write((unsigned short)float2int((angles[i]+pi)*(65535.0/2/pi)));
}
if (m_wspin.len2()==0) stm.Write(false);
else {
stm.Write(true); stm.Write(m_wspin);
}*/
return 1;
}
int CParticleEntity::SetStateFromSnapshot(CStream &stm, int flags)
{
bool bnz; int ver=0;
stm.ReadNumberInBits(ver,4);
if (ver!=SNAPSHOT_VERSION)
return 0;
if (!(flags & ssf_no_update)) {
if (m_pWorld->m_vars.bMultiplayer) {
stm.Read(bnz); if (bnz) {
stm.Read(m_pos);
stm.Read(bnz); if (bnz) {
stm.Read(m_vel);
stm.Read(bnz); if (bnz) {
m_bSliding = 1;
float yaw,pitch;
stm.Read(pitch); stm.Read(yaw);
m_slide_normal(cos_tpl(yaw)*cos_tpl(pitch),sin_tpl(yaw)*cos_tpl(pitch),sin_tpl(pitch));
} else m_bSliding = 0;
}
}
} else {
stm.Read(m_pos);
stm.Read(m_vel);
stm.Read(bnz); if (bnz) {
m_bSliding = 1;
float yaw,pitch;
stm.Read(pitch); stm.Read(yaw);
m_slide_normal(cos_tpl(yaw)*cos_tpl(pitch),sin_tpl(yaw)*cos_tpl(pitch),sin_tpl(pitch));
} else m_bSliding = 0;
}
if (m_bForceAwake!=0)
m_bForceAwake = -1;
} else {
if (m_pWorld->m_vars.bMultiplayer) {
stm.Read(bnz); if (bnz) {
stm.Seek(stm.GetReadPos()+sizeof(vectorf)*8);
stm.Read(bnz); if (bnz) {
stm.Seek(stm.GetReadPos()+sizeof(vectorf)*8);
stm.Read(bnz); if (bnz)
stm.Seek(stm.GetReadPos()+2*sizeof(float)*8);
}
}
} else {
stm.Seek(stm.GetReadPos()+2*sizeof(vectorf)*8);
stm.Read(bnz); if (bnz)
stm.Seek(stm.GetReadPos()+2*sizeof(float)*8);
}
}
/*stm.Read(bnz); if (bnz) {
unsigned short tmp; int i; vectorf axis(zero);
for(i=0,m_qspin.SetIdentity(); i<3; i++) {
axis[i] = 1;
//stm.Read(tmp); m_qspin*=quaternionf(tmp*(2*pi/65535.0)-pi, axis);
stm.Read(tmp); m_qspin = GetRotationAA((float)(tmp*(2*pi/65535.0)-pi), axis)*m_qspin;
axis[i] = 0;
}
}
stm.Read(bnz); if (bnz)
stm.Read(m_wspin);
else m_wspin.zero();*/
return 1;
}
int CParticleEntity::GetStatus(pe_status* _status)
{
if (CPhysicalEntity::GetStatus(_status))
return 1;
if (_status->type==pe_status_collisions::type_id) {
pe_status_collisions *status = (pe_status_collisions*)_status;
int i,n,nmax = min(status->len, sizeof(m_CollHistory)/sizeof(m_CollHistory[0]));
for(i=m_iCollHistory,n=0; n<nmax && m_CollHistory[i].age <= status->age; i=i-1&sizeof(m_CollHistory)/sizeof(m_CollHistory[0])-1,n++)
status->pHistory[n] = m_CollHistory[i];
if (status->bClearHistory) for(i=0;i<sizeof(m_CollHistory)/sizeof(m_CollHistory[0]);i++)
m_CollHistory[i].age = 1E10;
return status->len = n;
}
if (_status->type==pe_status_dynamics::type_id) {
pe_status_dynamics *status = (pe_status_dynamics*)_status;
vectorf gravity; float kAirResistance;
if (m_waterDensity>0 && (m_pos-m_waterPlane.origin)*m_waterPlane.n<0) {
gravity = m_waterGravity; kAirResistance = m_kWaterResistance;
} else {
gravity = m_gravity; kAirResistance = m_kAirResistance;
}
status->v = m_vel;
status->a = gravity+m_heading*m_accThrust-m_vel*kAirResistance+(m_heading^(m_heading^m_dirdown)).normalize()*m_kAccLift*m_vel.len();
status->w = m_wspin;
status->centerOfMass = m_pos;
return 1;
}
return 0;
}
int CParticleEntity::Action(pe_action* _action)
{
int res;
if (res = CPhysicalEntity::Action(_action))
return res;
if (_action->type==pe_action_impulse::type_id) {
pe_action_impulse *action = (pe_action_impulse*)_action;
vectorf P=action->impulse, L(zero);
if (!is_unused(action->momentum))
L = action->momentum;
else if (!is_unused(action->point))
L = action->point-m_pos^action->impulse;
m_vel += P/m_mass;
if (!(m_flags & particle_constant_orientation))
m_wspin += L/(0.4f*m_mass*m_dim);
return 1;
}
if (_action->type==pe_action_reset::type_id) {
m_vel.zero(); m_wspin.zero();
return 1;
}
return 0;
}
int CParticleEntity::Awake(int bAwake,int iSource)
{
if (bAwake)
m_bForceAwake = 1;
else {
m_bForceAwake = 0;
m_vel.zero();
}
return m_iSimClass;
}
int CParticleEntity::IsAwake(int ipart)
{
vectorf gravity = m_waterDensity>0 && (m_pos-m_waterPlane.origin)*m_waterPlane.n<0 ? m_waterGravity : m_gravity;
return m_vel.len2()<sqr(500.0f) && m_pos.z>-1000.0f && m_bForceAwake!=0 &&
(m_bForceAwake==1 || (m_vel.len2()>sqr(m_pWorld->m_vars.minSeparationSpeed) ||
m_CollHistory[m_iCollHistory].age>1E9 && !m_bSliding && gravity.len2()>0));
}
void CParticleEntity::StartStep(float time_interval)
{
m_timeStepPerformed = 0;
m_timeStepFull = time_interval;
}
float CParticleEntity::GetMaxTimeStep(float time_interval)
{
if (m_timeStepPerformed > m_timeStepFull-0.001f)
return time_interval;
return min_safe(m_timeStepFull-m_timeStepPerformed,time_interval);
}
int CParticleEntity::Step(float time_interval)
{
ray_hit hits[8];
pe_action_impulse ai;
pe_action_register_coll_event arce;
pe_status_dynamics sd;
vectorf pos0,vel0,heading0,vtang,vel_next;
float vn,vtang_len,rvtang_len,e,k,friction,vn0;
int i,nhits,bHit,flags;
vectorf gravity; float kAirResistance;
if (m_waterDensity>0 && (m_pos-m_waterPlane.origin)*m_waterPlane.n<0) {
gravity = m_waterGravity; kAirResistance = m_kWaterResistance;
} else {
gravity = m_gravity; kAirResistance = m_kAirResistance;
}
m_timeStepPerformed += time_interval;
if (m_pColliderToIgnore && m_pColliderToIgnore->m_iSimClass==7)
m_pColliderToIgnore = 0;
for(i=0;i<sizeof(m_CollHistory)/sizeof(m_CollHistory[0]);i++)
m_CollHistory[i].age += time_interval;
if (IsAwake()) {
FUNCTION_PROFILER( GetISystem(),PROFILE_PHYSICS );
PHYS_ENTITY_PROFILER
pos0 = m_pos; vel0 = m_vel;
if (!m_bSliding)
vel0 += gravity*time_interval*0.5f;
flags = m_flags;
m_pos += vel0*time_interval;
if (m_bSliding) {
if (m_pWorld->RayWorldIntersection(m_pos,m_slide_normal*(m_dim*-1.1f), ent_all,
m_iPierceability|(geom_colltype0|geom_colltype_ray)<<rwi_colltype_bit, hits,1, m_pColliderToIgnore,this))
{
m_slide_normal = hits[0].n;
m_pos = hits[0].pt+m_slide_normal*m_dimLying;
//if (m_dimLying!=m_dim)
// pos0 = m_pos;
if (m_flags&particle_no_roll || m_slide_normal.z<0.5f) { // always slide if the slope is steep enough
friction = max(0.0f, (m_pWorld->m_FrictionTable[m_surface_idx&NSURFACETYPES-1]+
m_pWorld->m_FrictionTable[hits[0].surface_idx&NSURFACETYPES-1])*0.5f);
if (m_slide_normal.z<0.5f)
friction = min(1.0f,friction); // limit sliding friction on slopes
vn = hits[0].n*vel0; vtang = vel0-hits[0].n*vn; vtang_len = vtang.len(); rvtang_len = vtang_len>1e-4 ? 1.0f/vtang_len:0;
if (((CPhysicalEntity*)hits[0].pCollider)->m_iSimClass>1) {
hits[0].pCollider->GetStatus(&sd);
vn0 = sd.v*hits[0].n;
} else vn0 = 0;
m_vel = vel0 = hits[0].n*max(vn0,vn) +
vtang*(max(0.0f,vtang_len-max(0.0f,-(vn+(m_gravity*hits[0].n)*time_interval))*friction)*rvtang_len);
m_wspin.zero(); m_qspin.SetIdentity();
if (!(m_flags & particle_constant_orientation))
(m_qrot = GetRotationV0V1(m_qrot*m_normal,hits[0].n)*m_qrot).Normalize();
//m_qrot.SetRotationV0V1(m_normal,hits[0].n); //m_qrot = quaternionf(m_normal,hits[0].n);
flags |= particle_constant_orientation;
} else {
friction = m_pWorld->m_FrictionTable[m_surface_idx&NSURFACETYPES-1];
vel0 = m_vel = (m_vel-m_slide_normal*(m_vel*m_slide_normal))*max(0.0f,1.0f-time_interval*friction);
m_wspin = m_slide_normal^m_vel*m_rdim;
}
if (m_flags & particle_single_contact)
gravity.zero();
else
gravity -= m_slide_normal*(m_slide_normal*gravity);
m_bForceAwake = ((CPhysicalEntity*)hits[0].pCollider)->m_iSimClass<=2 || m_timeForceAwake>40.0f ? -1:1;
} else {
m_bSliding = 0;
if (!(m_flags & particle_constant_orientation))
m_wspin = (m_heading^m_gravity).normalized()*((m_gravity*m_dirdown)*0.5f*m_rdim);
}
}
m_vel += (gravity + m_heading*m_accThrust - m_vel*kAirResistance +
(m_heading^(m_heading^m_dirdown)).normalize()*(m_kAccLift*m_vel.len()))*time_interval;
(m_heading=m_vel).normalize();
if (!(flags & particle_constant_orientation)) {
if (!(m_flags & particle_no_spin)) {
if (m_wspin.len2()*sqr(time_interval)<0.1f*0.1f) {
m_qspin += quaternionf(0,m_wspin*0.5f)*m_qspin*time_interval;
m_qspin.Normalize();
} else {
float wlen = m_wspin.len();
//m_qspin = quaternionf(wlen*time_interval,m_wspin/wlen)*m_qspin;
m_qspin = GetRotationAA(wlen*time_interval,m_wspin/wlen)*m_qspin;
}
} else
m_wspin.zero();
if (!(m_flags & particle_no_path_alignment)) {
vectorf dirbuf[3];
dirbuf[0] = m_dirdown^m_heading; dirbuf[1] = m_heading;
if (dirbuf[0].len2()<0.01f) dirbuf[0].SetOrthogonal(m_heading);
dirbuf[0].normalize(); dirbuf[2] = dirbuf[0]^dirbuf[1];
m_qrot = m_qspin*quaternionf((matrix3x3CMf&)dirbuf[0]);
} else
m_qrot = m_qspin;
}
bHit = 0;
if (m_pWorld->m_bWorldStep==2) {
CPhysicalEntity **pentlist;
pe_status_pos sp; sp.timeBack = 1;//time_interval;
vectorf posFixed;
int nents = m_pWorld->GetEntitiesAround(pos0-vectorf(m_dim,m_dim,m_dim),pos0+vectorf(m_dim,m_dim,m_dim),pentlist,ent_rigid);
hits[0].dist = hits[1].dist = 1E10f;
for(i=0;i<nents;i++) {
pentlist[i]->GetStatus(&sp);
posFixed = (pentlist[i]->m_qrot*!sp.q)*(pos0-sp.pos)+pentlist[i]->m_pos;
if (bHit = (m_pWorld->RayTraceEntity(pentlist[i],posFixed,pos0-posFixed+(pos0-posFixed).normalized()*(m_dim*0.97f),hits+1) &&
pentlist[i]->m_parts[hits[1].ipart].flags&geom_colltype0 && hits[1].dist<hits[0].dist))
hits[0] = hits[1];
}
if (bHit) { // ignore collisions with moving bodies if they push us through statics
heading0 = (hits[0].pt-pos0).normalized();
bHit ^= m_pWorld->RayWorldIntersection(pos0,hits[0].pt-pos0+heading0*m_dim,ent_terrain|ent_static,
m_iPierceability|(geom_colltype0|geom_colltype_ray)<<rwi_colltype_bit|rwi_ignore_back_faces, hits,1, m_pColliderToIgnore,this);
}
if (nhits = bHit)
pos0 = posFixed;
}
if (!bHit) {
heading0 = (m_pos-pos0).normalized();
nhits = m_pWorld->RayWorldIntersection(pos0,m_pos-pos0+heading0*m_dim, ent_all,
m_iPierceability|(geom_colltype0|geom_colltype_ray)<<rwi_colltype_bit|rwi_ignore_back_faces, hits,8, m_pColliderToIgnore,this);
bHit = isneg(-nhits) & (isneg(hits[0].dist+0.5f)^1);
for(i=nhits-1+(bHit^1);i>=(bHit^1);i--) { // register all hits in history
m_iCollHistory = m_iCollHistory+1 & sizeof(m_CollHistory)/sizeof(m_CollHistory[0])-1;
RigidBody *pbody = ((CPhysicalEntity*)hits[i].pCollider)->GetRigidBody(hits[i].ipart);
m_CollHistory[m_iCollHistory].pt = hits[i].pt-heading0*m_dim; // store not contact, but position of particle center at the time of contact
m_CollHistory[m_iCollHistory].n = hits[i].n; // it's better for explosions to be created at some distance from the wall
m_CollHistory[m_iCollHistory].v[0] = vel0;
m_CollHistory[m_iCollHistory].v[1] = pbody->v+(pbody->w^m_CollHistory[m_iCollHistory].pt-pbody->pos);
m_CollHistory[m_iCollHistory].mass[0] = m_mass;
m_CollHistory[m_iCollHistory].mass[1] = pbody->M;
m_CollHistory[m_iCollHistory].idCollider = m_pWorld->GetPhysicalEntityId(hits[i].pCollider);
m_CollHistory[m_iCollHistory].partid[0] = 0;
m_CollHistory[m_iCollHistory].partid[1] = hits[i].partid;
m_CollHistory[m_iCollHistory].idmat[0] = m_surface_idx;
m_CollHistory[m_iCollHistory].idmat[1] = hits[i].surface_idx;
m_CollHistory[m_iCollHistory].age = 0;
}
}
if (bHit) {
e = max(min((m_pWorld->m_BouncinessTable[m_surface_idx] + m_pWorld->m_BouncinessTable[hits[0].surface_idx])*0.5f, 1.0f), 0.0f);
float minv = ((CPhysicalEntity*)hits[0].pCollider)->GetMassInv();
k = m_mass*minv/(1+m_mass*minv);
if (((CPhysicalEntity*)hits[0].pCollider)->m_iSimClass>0) {
RigidBody *pbody = ((CPhysicalEntity*)hits[0].pCollider)->GetRigidBody(hits[0].ipart);
vectorf vrel = vel0-pbody->v-(pbody->w^hits[0].pt-pbody->pos);
if (vel0.len2()>sqr(m_minBounceVel)) {
ai.point = hits[0].pt;
ai.impulse = vrel*(m_mass*pbody->M/(m_mass+pbody->M)*(1+e));
ai.ipart = hits[0].ipart;
hits[0].pCollider->Action(&ai);
arce.pt = hits[0].pt;
arce.n = hits[0].n;
arce.v = m_vel;
arce.collMass = m_mass;
arce.pCollider = this;
arce.partid[0] = hits[0].partid;
arce.partid[1] = 0;
arce.idmat[0] = hits[0].surface_idx;
arce.idmat[1] = m_surface_idx;
hits[0].pCollider->Action(&arce);
}
}
vn = hits[0].n*vel0; vtang = vel0-hits[0].n*vn;
if (vn>-m_minBounceVel || m_dimLying<m_dim*0.3f)
e = 0;
m_vel = vel0-hits[0].n*(vn*(1-k)*(1+e));
if (sqr(m_dim)<(hits[0].pt-pos0).len2())
m_pos = hits[0].pt - heading0*m_dim;
else
m_pos = pos0;
if (m_vel.len2()<sqr(m_pWorld->m_vars.minSeparationSpeed) || m_flags & particle_single_contact) {
m_vel.zero(); m_wspin.zero(); m_qspin.SetIdentity();
if (m_dim!=m_dimLying)
m_pos = hits[0].pt+hits[0].n*m_dimLying;
m_bSliding = 1; m_slide_normal = hits[0].n;
if (!(flags & particle_constant_orientation))
m_qrot = GetRotationV0V1(m_qrot*m_normal,hits[0].n)*m_qrot;
//m_qrot = quaternionf(m_normal,hits[0].n);
} else {
vel_next = m_vel + (gravity + m_heading*m_accThrust - m_vel*kAirResistance +
(m_heading^(m_heading^m_dirdown)).normalize()*(m_kAccLift*m_vel.len()))*time_interval;
if (vel_next*hits[0].n<m_pWorld->m_vars.minSeparationSpeed) {
if (m_dim!=m_dimLying)
m_pos = hits[0].pt+hits[0].n*m_dimLying;
m_bSliding = 1; m_slide_normal = hits[0].n;
if (m_flags & particle_no_roll && !(m_flags & particle_constant_orientation))
m_qrot = GetRotationV0V1(m_qrot*m_normal,hits[0].n)*m_qrot;
//m_qrot = quaternionf(m_normal,hits[0].n);
}
if (m_flags & particle_no_roll) m_wspin.zero();
else m_wspin = (hits[0].n^vtang)*m_rdim;
}
if (((CPhysicalEntity*)hits[0].pCollider)->m_iSimClass>1) {
hits[0].pCollider->GetStatus(&sd);
m_vel += hits[0].n*(sd.v*hits[0].n);
}
m_bForceAwake = ((CPhysicalEntity*)hits[0].pCollider)->m_iSimClass<=2 || m_timeForceAwake>40.0f ? -1:1;
}
i = (m_bForceAwake ^ m_bForceAwake>>31) & 1;
m_timeForceAwake = m_timeForceAwake*i + time_interval*i;
m_sleepTime = 0;
m_BBox[0] = m_pos-vectorf(m_dim,m_dim,m_dim);
m_BBox[1] = m_pos+vectorf(m_dim,m_dim,m_dim);
if (m_flags & particle_traceable)
m_pWorld->RepositionEntity(this, 1);
} else
m_sleepTime += time_interval;
return 1;
}
int CParticleEntity::RayTrace(CRayGeom *pRay,geom_contact *&pcontacts)
{
static geom_contact g_ParticleContact;
prim_inters inters;
box abox;
abox.Basis.SetRow(2,m_qrot*m_normal);
abox.Basis.SetRow(0,m_qrot*GetOrthogonal(m_normal).normalized());
abox.Basis.SetRow(1,abox.Basis.GetRow(2)^abox.Basis.GetRow(0));
abox.size(m_dim,m_dim,m_dimLying);
abox.center = m_pos;
if (box_ray_intersection(&abox,&pRay->m_ray,&inters)) {
pcontacts = &g_ParticleContact;
pcontacts->pt = inters.pt[0];
pcontacts->t = (inters.pt[0]-pRay->m_ray.origin)*pRay->m_dirn;
pcontacts->id[0] = m_surface_idx;
pcontacts->iNode[0] = 0;
pcontacts->n = inters.n;
return 1;
}
return 0;
}
void CParticleEntity::DrawHelperInformation(void (*DrawLineFunc)(float*,float*), int flags)
{
CPhysicalEntity::DrawHelperInformation(DrawLineFunc,flags);
if (flags & pe_helper_geometry) {
box abox;
abox.Basis.SetRow(2,m_qrot*m_normal);
abox.Basis.SetRow(0,m_qrot*GetOrthogonal(m_normal));
abox.Basis.SetRow(1,abox.Basis.GetRow(2)^abox.Basis.GetRow(0));
abox.center = m_pos;
int i,j;
vectorf pt[8];
for(i=0;i<8;i++)
pt[i] = vectorf(m_dim*((i<<1&2)-1),m_dim*((i&2)-1),m_dimLying*((i>>1&2)-1))*abox.Basis+abox.center;
for(i=0;i<8;i++) for(j=0;j<3;j++) if (i&1<<j)
DrawLineFunc(pt[i],pt[i^1<<j]);
}
}
void CParticleEntity::GetMemoryStatistics(ICrySizer *pSizer)
{
CPhysicalEntity::GetMemoryStatistics(pSizer);
if (GetType()==PE_PARTICLE)
pSizer->AddObject(this, sizeof(CParticleEntity));
}

View File

@@ -0,0 +1,66 @@
//////////////////////////////////////////////////////////////////////
//
// Particle Entity header
//
// File: particleentity.h
// Description : CParticleEntity class declaration
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#ifndef particleentity_h
#define particleentity_h
#pragma once
class CParticleEntity : public CPhysicalEntity {
public:
CParticleEntity(CPhysicalWorld *pworld);
virtual ~CParticleEntity();
virtual pe_type GetType() { return PE_PARTICLE; }
virtual int SetParams(pe_params*);
virtual int GetParams(pe_params*);
virtual int GetStatus(pe_status*);
virtual int Action(pe_action*);
virtual int Awake(int bAwake=1,int iSource=0);
virtual int IsAwake(int ipart=-1);
virtual int RayTrace(CRayGeom *pRay, geom_contact *&pcontacts);
virtual void ComputeBBox() { vectorf sz(m_dim,m_dim,m_dim); m_BBox[0]=m_pos-sz; m_BBox[1]=m_pos+sz; }
enum snapver { SNAPSHOT_VERSION = 3 };
virtual int GetStateSnapshot(class CStream &stm,float time_back=0,int flags=0);
virtual int SetStateFromSnapshot(class CStream &stm, int flags);
virtual void StartStep(float time_interval);
virtual float GetMaxTimeStep(float time_interval);
virtual int Step(float time_interval);
virtual void DrawHelperInformation(void (*DrawLineFunc)(float*,float*), int flags);
virtual void GetMemoryStatistics(ICrySizer *pSizer);
float m_mass,m_dim,m_rdim,m_dimLying;
float m_kAirResistance,m_kWaterResistance, m_accThrust, m_kAccLift;
vectorf m_gravity,m_waterGravity,m_dirdown,m_normal;
vectorf m_heading,m_vel,m_wspin;
quaternionf m_qspin;
float m_minBounceVel;
int m_surface_idx;
CPhysicalEntity *m_pColliderToIgnore;
int m_iPierceability;
int m_bSliding;
vectorf m_slide_normal;
float m_timeSurplus;
plane m_waterPlane;
float m_waterDensity;
int m_bForceAwake;
float m_timeStepPerformed,m_timeStepFull;
float m_timeForceAwake;
float m_sleepTime;
coll_history_item m_CollHistory[4];
int m_iCollHistory;
};
#endif

View File

@@ -0,0 +1,620 @@
//////////////////////////////////////////////////////////////////////
//
// Physical Entity
//
// File: physicalentity.cpp
// Description : PhysicalEntity class implementation
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "bvtree.h"
#include "geometry.h"
#include "rigidbody.h"
#include "physicalplaceholder.h"
#include "physicalentity.h"
#include "geoman.h"
#include "physicalworld.h"
RigidBody g_StaticRigidBody;
CPhysicalEntity g_StaticPhysicalEntity(0);
CPhysicalEntity::CPhysicalEntity(CPhysicalWorld *pworld)
{
m_pos.zero(); m_qrot.SetIdentity();
m_BBox[0].zero(); m_BBox[1].zero();
m_iSimClass = 0; m_iPrevSimClass = -1;
m_nGridThunks = m_nGridThunksAlloc = 0;
m_pGridThunks = 0;
m_ig[0].x=m_ig[1].x=m_ig[0].y=m_ig[1].y = -2;
m_prev = m_next = 0; m_bProcessed = 0;
m_nRefCount = 0;//1; 0 means that initially no other physical entity references this one
m_nParts = 0;
m_nPartsAlloc = 1;
m_parts = &m_defpart;
m_iLastIdx = 0;
m_pWorld = pworld;
m_pOuterEntity = 0;
m_pBoundingGeometry = 0;
m_bProcessed_aux = 0;
m_nColliders = m_nCollidersAlloc = 0;
m_pColliders = 0;
m_iGroup = -1;
m_bMoved = 0;
m_id = -1;
m_pForeignData = 0;
m_iForeignData = m_iForeignFlags = 0;
m_timeIdle = m_maxTimeIdle = 0;
m_bPermanent = 1;
m_pEntBuddy = 0;
m_flags = pef_pushable_by_players|pef_traceable;
}
CPhysicalEntity::~CPhysicalEntity()
{
for(int i=0;i<m_nParts;i++) if (m_parts[i].pPhysGeom) {
m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeom);
if (m_parts[i].pPhysGeomProxy!=m_parts[i].pPhysGeom)
m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeomProxy);
}
if (m_pGridThunks) delete[] m_pGridThunks;
if (m_parts!=&m_defpart) delete[] m_parts;
if (m_pColliders) delete[] m_pColliders;
}
void CPhysicalEntity::ComputeBBox()
{
if (m_nParts==0)
m_BBox[0]=m_BBox[1]=m_pos;
else {
IGeometry *pGeom[3];
matrix3x3f R;
int i,j; box abox; vectorf sz,pos;
m_BBox[0]=vectorf(MAX); m_BBox[1]=vectorf(MIN);
for(i=0;i<m_nParts;i++) {
pGeom[0] = m_parts[i].pPhysGeomProxy->pGeom;
pGeom[1]=pGeom[2] = m_parts[i].pPhysGeom->pGeom;
j=0; do {
pGeom[j]->GetBBox(&abox);
//(m_qrot*m_parts[i].q).getmatrix(R); //Q2M_IVO
R = matrix3x3f(m_qrot*m_parts[i].q);
abox.Basis *= R.T();
sz = (abox.size*abox.Basis.Fabs())*m_parts[i].scale;
pos = m_pos+m_qrot*(m_parts[i].pos+m_parts[i].q*abox.center*m_parts[i].scale);
m_parts[i].BBox[0] = pos-sz;
m_parts[i].BBox[1] = pos+sz;
m_BBox[0].x = min_safe(m_BBox[0].x, m_parts[i].BBox[0].x);
m_BBox[0].y = min_safe(m_BBox[0].y, m_parts[i].BBox[0].y);
m_BBox[0].z = min_safe(m_BBox[0].z, m_parts[i].BBox[0].z);
m_BBox[1].x = max_safe(m_BBox[1].x, m_parts[i].BBox[1].x);
m_BBox[1].y = max_safe(m_BBox[1].y, m_parts[i].BBox[1].y);
m_BBox[1].z = max_safe(m_BBox[1].z, m_parts[i].BBox[1].z);
j++;
} while(pGeom[j]!=pGeom[j-1]);
}
}
if (m_pEntBuddy) {
m_pEntBuddy->m_BBox[0] = m_BBox[0];
m_pEntBuddy->m_BBox[1] = m_BBox[1];
}
}
int CPhysicalEntity::SetParams(pe_params *_params)
{
if (_params->type==pe_params_pos::type_id) {
pe_params_pos *params = (pe_params_pos*)_params;
get_xqs_from_matrices(params->pMtx3x3,params->pMtx3x3T,params->pMtx4x4,params->pMtx4x4T, params->pos,params->q,params->scale);
ENTITY_VALIDATE("CPhysicalEntity:SetParams(pe_params_pos)",params);
int bPosChanged = 0;
if (!is_unused(params->pos)) { m_pos = params->pos; bPosChanged=1; }
if (!is_unused(params->q)) { m_qrot = params->q; bPosChanged=1; }
if (!is_unused(params->iSimClass) && m_iSimClass>=0 && m_iSimClass<7) {
m_iSimClass = params->iSimClass;
m_pWorld->RepositionEntity(this,2);
}
if (!is_unused(params->scale)) {
for(int i=0;i<m_nParts;i++) {
m_parts[i].pos *= params->scale/m_parts[i].scale;
m_parts[i].scale = params->scale;
} bPosChanged=1;
}
if (params->bRecalcBounds && bPosChanged) {
CPhysicalEntity **pentlist;
// make triggers aware of the object's movements
if (!(m_flags & pef_never_affect_triggers))
m_pWorld->GetEntitiesAround(m_BBox[0],m_BBox[1],pentlist,ent_triggers,this);
ComputeBBox();
m_pWorld->RepositionEntity(this);
if (!(m_flags & pef_never_affect_triggers))
m_pWorld->GetEntitiesAround(m_BBox[0],m_BBox[1],pentlist,ent_triggers,this);
}
return 1;
}
if (_params->type==pe_params_bbox::type_id) {
pe_params_bbox *params = (pe_params_bbox*)_params;
ENTITY_VALIDATE("CPhysicalEntity::SetParams(pe_params_bbox)",params);
if (!is_unused(params->BBox[0])) m_BBox[0] = params->BBox[0];
if (!is_unused(params->BBox[1])) m_BBox[1] = params->BBox[1];
if (m_pEntBuddy) {
m_pEntBuddy->m_BBox[0] = m_BBox[0];
m_pEntBuddy->m_BBox[1] = m_BBox[1];
}
m_pWorld->RepositionEntity(this,1);
return 1;
}
if (_params->type==pe_params_part::type_id) {
pe_params_part *params = (pe_params_part*)_params;
int i = params->ipart;
if (i<0)
for(i=0;i<m_nParts && m_parts[i].id!=params->partid;i++);
if (i>=m_nParts)
return 0;
get_xqs_from_matrices(params->pMtx3x3,params->pMtx3x3T,params->pMtx4x4,params->pMtx4x4T, params->pos,params->q,params->scale);
ENTITY_VALIDATE("CPhysicalEntity:SetParams(pe_params_part)",params);
if (!is_unused(params->pos.x)) m_parts[i].pos = params->pos;
if (!is_unused(params->q)) m_parts[i].q = params->q;
if (!is_unused(params->scale)) m_parts[i].scale = params->scale;
if (!is_unused(params->mass)) m_parts[i].mass = params->mass;
if (!is_unused(params->density)) m_parts[i].mass = m_parts[i].pPhysGeom->V*cube(m_parts[i].scale)*params->density;
if (!is_unused(params->pPhysGeom) && params->pPhysGeom!=m_parts[i].pPhysGeom) {
if (m_parts[i].pPhysGeom==m_parts[i].pPhysGeomProxy)
m_parts[i].pPhysGeomProxy = params->pPhysGeom;
m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeom);
m_parts[i].pPhysGeom = params->pPhysGeom;
m_pWorld->GetGeomManager()->AddRefGeometry(params->pPhysGeom);
}
if (!is_unused(params->pPhysGeomProxy) && params->pPhysGeomProxy!=m_parts[i].pPhysGeomProxy) {
m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeomProxy);
m_parts[i].pPhysGeomProxy = params->pPhysGeomProxy;
m_pWorld->GetGeomManager()->AddRefGeometry(params->pPhysGeomProxy);
}
m_parts[i].flags = m_parts[i].flags & params->flagsAND | params->flagsOR;
m_parts[i].flagsCollider = m_parts[i].flagsCollider & params->flagsColliderAND | params->flagsColliderOR;
if (params->bRecalcBBox)
ComputeBBox();
return i+1;
}
if (_params->type==pe_params_outer_entity::type_id) {
m_pOuterEntity = (CPhysicalEntity*)((pe_params_outer_entity*)_params)->pOuterEntity;
m_pBoundingGeometry = (CGeometry*)((pe_params_outer_entity*)_params)->pBoundingGeometry;
return 1;
}
if (_params->type==pe_params_foreign_data::type_id) {
pe_params_foreign_data *params = (pe_params_foreign_data*)_params;
if (!is_unused(params->iForeignData)) m_iForeignData = params->iForeignData;
if (!is_unused(params->pForeignData)) m_pForeignData = params->pForeignData;
if (!is_unused(params->iForeignFlags)) m_iForeignFlags = params->iForeignFlags;
if (m_pEntBuddy) {
m_pEntBuddy->m_pForeignData = m_pForeignData;
m_pEntBuddy->m_iForeignData = m_iForeignData;
m_pEntBuddy->m_iForeignFlags = m_iForeignFlags;
}
return 1;
}
if (_params->type==pe_params_flags::type_id) {
pe_params_flags *params = (pe_params_flags*)_params;
int flags = m_flags;
if (!is_unused(params->flags)) m_flags = params->flags;
if (!is_unused(params->flagsAND)) m_flags &= params->flagsAND;
if (!is_unused(params->flagsOR)) m_flags |= params->flagsOR;
if (m_flags&pef_traceable && m_ig[0].x==-3) {
m_ig[0].x=m_ig[1].x=m_ig[0].y=m_ig[1].y = -2;
if (m_pos.len2()>0)
m_pWorld->RepositionEntity(this,1);
}
if (!(m_flags&pef_traceable) && m_ig[0].x!=-3) {
m_pWorld->DetachEntityGridThunks(this);
m_ig[0].x=m_ig[1].x=m_ig[0].y=m_ig[1].y = -3;
}
return 1;
}
return 0;
}
int CPhysicalEntity::GetParams(pe_params *_params)
{
if (_params->type==pe_params_bbox::type_id) {
pe_params_bbox *params = (pe_params_bbox*)_params;
params->BBox[0] = m_BBox[0];
params->BBox[1] = m_BBox[1];
return 1;
}
if (_params->type==pe_params_outer_entity::type_id) {
((pe_params_outer_entity*)_params)->pOuterEntity = m_pOuterEntity;
((pe_params_outer_entity*)_params)->pBoundingGeometry = m_pBoundingGeometry;
return 1;
}
if (_params->type==pe_params_foreign_data::type_id) {
pe_params_foreign_data *params = (pe_params_foreign_data*)_params;
params->iForeignData = m_iForeignData;
params->pForeignData = m_pForeignData;
params->iForeignFlags = m_iForeignFlags;
return 1;
}
if (_params->type==pe_params_part::type_id) {
pe_params_part *params = (pe_params_part*)_params;
int i;
if (params->ipart==-1 && params->partid>=0) {
for(i=0;i<m_nParts && m_parts[i].id!=params->partid;i++);
if (i==m_nParts) return 0;
} else
i = params->ipart;
params->partid = m_parts[params->ipart = i].id;
params->pos = m_parts[i].pos;
params->q = m_parts[i].q;
params->scale = m_parts[i].scale;
if (params->pMtx3x3) //resq.getmatrix((matrix3x3f&)*status->pMtx3x3) *= resscale; //Q2M_IVO
(matrix3x3f&)*params->pMtx3x3 = (matrix3x3f(m_parts[i].q)*m_parts[i].scale);
if (params->pMtx3x3T) //resq.getmatrix((matrix3x3Tf&)*params->pMtx3x3T) *= resscale; //Q2M_IVO
(matrix3x3Tf&)*params->pMtx3x3T=(matrix3x3f(m_parts[i].q)*m_parts[i].scale);
if (params->pMtx4x4) //(resq.getmatrix((matrix3x3in4x4f&)*params->pMtx4x4)*=resscale).SetColumn(3,respos); //Q2M_IVO
((matrix3x3in4x4f&)*params->pMtx4x4 = (matrix3x3f(m_parts[i].q)*m_parts[i].scale)).SetColumn(3,m_parts[i].pos);
if (params->pMtx4x4T) //(resq.getmatrix((matrix3x3in4x4Tf&)*params->pMtx4x4T)*=resscale).SetColumn(3,respos); //Q2M_IVO
((matrix3x3in4x4Tf&)*params->pMtx4x4T = (matrix3x3f(m_parts[i].q)*m_parts[i].scale)).SetColumn(3,m_parts[i].pos);
params->flagsOR=params->flagsAND = m_parts[i].flags;
params->flagsColliderOR=params->flagsColliderAND = m_parts[i].flagsCollider;
params->mass = m_parts[i].mass;
params->density = m_parts[i].pPhysGeomProxy->V>0 ?
m_parts[i].mass/(m_parts[i].pPhysGeomProxy->V*cube(m_parts[i].scale)) : 0;
params->pPhysGeom = m_parts[i].pPhysGeom;
params->pPhysGeomProxy = m_parts[i].pPhysGeomProxy;
}
if (_params->type==pe_params_flags::type_id) {
((pe_params_flags*)_params)->flags = m_flags;
return 1;
}
return 0;
}
int CPhysicalEntity::GetStatus(pe_status *_status)
{
if (_status->type==pe_status_pos::type_id) {
pe_status_pos *status = (pe_status_pos*)_status;
vectorf respos;
quaternionf resq;
float resscale;
int i;
if (status->ipart==-1 && status->partid>=0) {
for(i=0;i<m_nParts && m_parts[i].id!=status->partid;i++);
if (i==m_nParts) return 0;
} else
i = status->ipart;
if (i==-1) {
respos=m_pos; resq=m_qrot; resscale=1.0f;
for(i=0,status->flagsOR=0,status->flagsAND=-1;i<m_nParts;i++)
status->flagsOR|=m_parts[i].flags, status->flagsAND&=m_parts[i].flags;
if (m_nParts>0) {
status->pGeom = m_parts[0].pPhysGeom->pGeom;
status->pGeomProxy = m_parts[0].pPhysGeomProxy->pGeom;
} else
status->pGeom = status->pGeomProxy = 0;
} else {
if (status->flags & status_local) {
respos = m_parts[i].pos; resq = m_parts[i].q;
} else {
respos = m_pos+m_qrot*m_parts[i].pos;
resq = m_qrot*m_parts[i].q;
}
resscale = m_parts[i].scale;
status->flagsOR = status->flagsAND = m_parts[i].flags;
status->pGeom = m_parts[i].pPhysGeom->pGeom;
status->pGeomProxy = m_parts[i].pPhysGeomProxy->pGeom;
}
status->pos = respos;
status->q = resq;
status->scale = resscale;
status->iSimClass = m_iSimClass;
if (status->pMtx3x3) //resq.getmatrix((matrix3x3f&)*status->pMtx3x3) *= resscale; //Q2M_IVO
(matrix3x3f&)*status->pMtx3x3 = (matrix3x3f(resq)*resscale);
if (status->pMtx3x3T) //resq.getmatrix((matrix3x3Tf&)*status->pMtx3x3T) *= resscale; //Q2M_IVO
(matrix3x3Tf&)*status->pMtx3x3T=(matrix3x3f(resq)*resscale);
if (status->pMtx4x4) //(resq.getmatrix((matrix3x3in4x4f&)*status->pMtx4x4)*=resscale).SetColumn(3,respos); //Q2M_IVO
((matrix3x3in4x4f&)*status->pMtx4x4 = (matrix3x3f(resq)*resscale)).SetColumn(3,respos);
if (status->pMtx4x4T) //(resq.getmatrix((matrix3x3in4x4Tf&)*status->pMtx4x4T)*=resscale).SetColumn(3,respos); //Q2M_IVO
((matrix3x3in4x4Tf&)*status->pMtx4x4T = (matrix3x3f(resq)*resscale)).SetColumn(3,respos);
status->BBox[0] = m_BBox[0]-m_pos;
status->BBox[1] = m_BBox[1]-m_pos;
return 1;
}
if (_status->type==pe_status_id::type_id) {
pe_status_id *status = (pe_status_id*)_status;
int ipart = status->ipart;
if (ipart<0)
for(ipart=0;ipart<m_nParts-1 && m_parts[ipart].id!=status->partid;ipart++);
if (ipart>=m_nParts)
return 0;
phys_geometry *pgeom = status->bUseProxy ? m_parts[ipart].pPhysGeomProxy : m_parts[ipart].pPhysGeom;
if ((unsigned int)status->iPrim >= (unsigned int)pgeom->pGeom->GetPrimitiveCount() ||
pgeom->pGeom->GetType()==GEOM_TRIMESH && status->iFeature>2)
return 0;
status->id = pgeom->pGeom->GetPrimitiveId(status->iPrim, status->iFeature);
status->id = status->id&~(status->id>>31) | m_parts[ipart].surface_idx&status->id>>31;
return 1;
}
if (_status->type==pe_status_nparts::type_id)
return m_nParts;
if (_status->type==pe_status_awake::type_id)
return IsAwake();
if (_status->type==pe_status_contains_point::type_id)
return IsPointInside(((pe_status_contains_point*)_status)->pt);
if (_status->type==pe_status_caps::type_id) {
pe_status_caps *status = (pe_status_caps*)_status;
status->bCanAlterOrientation = 0;
return 1;
}
return 0;
};
int CPhysicalEntity::Action(pe_action *_action)
{
if (_action->type==pe_action_awake::type_id && m_iSimClass>=0 && m_iSimClass<7) {
Awake(((pe_action_awake*)_action)->bAwake,1);
return 1;
}
if (_action->type==pe_action_remove_all_parts::type_id) {
for(int i=m_nParts-1;i>=0;i--)
RemoveGeometry(m_parts[i].id);
return 1;
}
return 0;
}
int CPhysicalEntity::AddGeometry(phys_geometry *pgeom, pe_geomparams* params, int id)
{
if (!pgeom)
return -1;
box abox; pgeom->pGeom->GetBBox(&abox);
float mindim=min(min(abox.size.x,abox.size.y),abox.size.z), mindims=mindim*params->scale;
float maxdim=max(max(abox.size.x,abox.size.y),abox.size.z), maxdims=maxdim*params->scale;
if (id>=0) {
int i; for(i=0;i<m_nParts && m_parts[i].id!=id;i++);
if (i<m_nParts) {
if (params->flags & geom_proxy) {
if (pgeom) {
if (m_parts[i].pPhysGeomProxy!=pgeom)
m_pWorld->GetGeomManager()->AddRefGeometry(pgeom);
m_parts[i].pPhysGeomProxy = pgeom;
if (mindims<0.15f)
m_parts[i].flags |= geom_has_thin_parts;
}
} else {
m_parts[i].pos = params->pos;
m_parts[i].q = params->q;
}
return id;
}
}
get_xqs_from_matrices(params->pMtx3x3,params->pMtx3x3T,params->pMtx4x4,params->pMtx4x4T, params->pos,params->q,params->scale);
ENTITY_VALIDATE_ERRCODE("CPhysicalEntity:AddGeometry",params,-1);
if (m_nParts==m_nPartsAlloc) {
geom *pparts = m_parts;
memcpy(m_parts = new geom[m_nPartsAlloc=m_nPartsAlloc+4&~3], pparts, sizeof(geom)*m_nParts);
if (pparts!=&m_defpart) delete[] pparts;
}
m_parts[m_nParts].id = id<0 ? m_iLastIdx++:id;
m_parts[m_nParts].pPhysGeom = m_parts[m_nParts].pPhysGeomProxy = pgeom;
m_pWorld->GetGeomManager()->AddRefGeometry(pgeom);
m_parts[m_nParts].surface_idx = pgeom->surface_idx;
if (!is_unused(params->surface_idx)) m_parts[m_nParts].surface_idx = params->surface_idx;
m_parts[m_nParts].flags = params->flags & ~geom_proxy;
m_parts[m_nParts].flagsCollider = params->flagsCollider;
m_parts[m_nParts].pos = params->pos;
m_parts[m_nParts].q = params->q;
m_parts[m_nParts].scale = params->scale;
if (is_unused(params->minContactDist)) {
m_parts[m_nParts].minContactDist = max(maxdims*0.03f,mindims*(mindims<maxdims*0.3f ? 0.4f:0.1f));
if (mindims<0.15f)
m_parts[m_nParts].flags |= geom_has_thin_parts;
} else
m_parts[m_nParts].minContactDist = params->minContactDist;
m_parts[m_nParts].maxdim = maxdim;
m_nParts++;
if (params->bRecalcBBox) {
ComputeBBox();
m_pWorld->RepositionEntity(this,1);
}
return m_parts[m_nParts-1].id;
}
void CPhysicalEntity::RemoveGeometry(int id)
{
for(int i=0;i<m_nParts;i++) if (m_parts[i].id==id) {
m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeom);
if (m_parts[i].pPhysGeomProxy!=m_parts[i].pPhysGeom)
m_pWorld->GetGeomManager()->UnregisterGeometry(m_parts[i].pPhysGeomProxy);
for(;i<m_nParts-1;i++) m_parts[i]=m_parts[i+1];
m_nParts--;
ComputeBBox();
m_pWorld->RepositionEntity(this,1);
return;
}
}
RigidBody *CPhysicalEntity::GetRigidBody(int ipart)
{
g_StaticRigidBody.P.zero(); g_StaticRigidBody.v.zero();
g_StaticRigidBody.L.zero(); g_StaticRigidBody.w.zero();
return &g_StaticRigidBody;
}
int CPhysicalEntity::IsPointInside(vectorf pt)
{
pt = (pt-m_pos)*m_qrot;
if (m_pBoundingGeometry)
return m_pBoundingGeometry->PointInsideStatus(pt);
for(int i=0;i<m_nParts;i++) if ((m_parts[i].flags & geom_collides) &&
m_parts[i].pPhysGeom->pGeom->PointInsideStatus((pt-m_parts[i].pos)*m_parts[i].q))
return 1;
return 0;
}
void CPhysicalEntity::AlertNeighbourhoodND()
{
int i;
if (m_iSimClass>3)
return;
for(i=0;i<m_nColliders;i++) if (m_pColliders[i]!=this) {
m_pColliders[i]->RemoveCollider(this);
m_pColliders[i]->Awake();
m_pColliders[i]->Release();
m_nRefCount--;
}
m_nColliders = 0;
if (m_nRefCount>0 || m_flags&pef_always_notify_on_deletion) {
CPhysicalEntity **pentlist;
vectorf inflator = (m_BBox[1]-m_BBox[0])*1E-3f+vectorf(4,4,4)*m_pWorld->m_vars.maxContactGap;
for(i=m_pWorld->GetEntitiesAround(m_BBox[0]-inflator,m_BBox[1]+inflator, pentlist,
ent_sleeping_rigid|ent_rigid|ent_living|ent_independent|ent_triggers)-1; i>=0; i--)
pentlist[i]->Awake();
}
}
int CPhysicalEntity::RemoveCollider(CPhysicalEntity *pCollider, bool bRemoveAlways)
{
if (m_pColliders && m_iSimClass>0) {
int i,islot; for(i=0;i<m_nColliders && m_pColliders[i]!=pCollider;i++);
if (i<m_nColliders) {
for(islot=i;i<m_nColliders-1;i++) m_pColliders[i] = m_pColliders[i+1];
if (pCollider!=this)
pCollider->Release();
m_nColliders--; return islot;
}
}
return -1;
}
int CPhysicalEntity::AddCollider(CPhysicalEntity *pCollider)
{
if (m_iSimClass==0)
return 1;
int i,j;
for(i=0;i<m_nColliders && m_pColliders[i]!=pCollider;i++);
if (i==m_nColliders) {
if (m_nColliders==m_nCollidersAlloc) {
CPhysicalEntity **pColliders = m_pColliders;
memcpy(m_pColliders = new (CPhysicalEntity*[m_nCollidersAlloc+=8]), pColliders, sizeof(CPhysicalEntity*)*m_nColliders);
if (pColliders) delete[] pColliders;
}
for(i=0;i<m_nColliders && pCollider->GetMassInv()>m_pColliders[i]->GetMassInv();i++);
for(j=m_nColliders-1; j>=i; j--) m_pColliders[j+1] = m_pColliders[j];
m_pColliders[i] = pCollider; m_nColliders++;
if (pCollider!=this)
pCollider->AddRef();
}
return i;
}
void CPhysicalEntity::DrawHelperInformation(void (*DrawLineFunc)(float*,float*), int flags)
{
if (flags & pe_helper_bbox) {
int i,j;
vectorf sz,center,pt[8];
center = (m_BBox[1]+m_BBox[0])*0.5f;
sz = (m_BBox[1]-m_BBox[0])*0.5f;
for(i=0;i<8;i++)
pt[i] = vectorf(sz.x*((i<<1&2)-1),sz.y*((i&2)-1),sz.z*((i>>1&2)-1))+center;
for(i=0;i<8;i++) for(j=0;j<3;j++) if (i&1<<j)
DrawLineFunc(pt[i],pt[i^1<<j]);
}
if (flags & pe_helper_geometry) {
int iLevel = flags>>16;
geom_world_data gwd;
for(int i=0;i<m_nParts;i++) {
//(m_qrot*m_parts[i].q).getmatrix(gwd.R); //Q2M_IVO
gwd.R = matrix3x3f(m_qrot*m_parts[i].q);
gwd.offset = m_pos + m_qrot*m_parts[i].pos;
gwd.scale = m_parts[i].scale;
m_parts[i].pPhysGeom->pGeom->DrawWireframe(DrawLineFunc,&gwd, iLevel);
if (m_parts[i].pPhysGeomProxy!=m_parts[i].pPhysGeom)
m_parts[i].pPhysGeomProxy->pGeom->DrawWireframe(DrawLineFunc,&gwd, iLevel);
}
}
}
void CPhysicalEntity::GetMemoryStatistics(ICrySizer *pSizer)
{
if (GetType()==PE_STATIC)
pSizer->AddObject(this, sizeof(CPhysicalEntity));
if (m_parts!=&m_defpart)
pSizer->AddObject(m_parts, m_nParts*sizeof(m_parts[0]));
pSizer->AddObject(m_pGridThunks, m_nGridThunksAlloc*sizeof(m_pGridThunks[0]));
pSizer->AddObject(m_pColliders, m_nCollidersAlloc*sizeof(m_pColliders[0]));
}
int CPhysicalEntity::GetStateSnapshotTxt(char *txtbuf,int szbuf, float time_back)
{
CStream stm;
GetStateSnapshot(stm,time_back);
int size=bin2ascii(stm.GetPtr(),(stm.GetSize()-1>>3)+1,(unsigned char*)txtbuf);
/*
// debugging
static char test[1024*16];
int testsize=ascii2bin((const unsigned char*)txtbuf,size,(unsigned char*)test);
if(memcmp(test,stm.GetPtr(),testsize)!=0)
{
char str[256];
sprintf(str,"%d %d\n",size,testsize);
OutputDebugString(str);
}
*/
return size;
}
void CPhysicalEntity::SetStateFromSnapshotTxt(const char *txtbuf,int szbuf)
{
CStream stm;
stm.SetSize(ascii2bin((const unsigned char*)txtbuf,szbuf,stm.GetPtr())*8);
SetStateFromSnapshot(stm);
}

131
CryPhysics/physicalentity.h Normal file
View File

@@ -0,0 +1,131 @@
//////////////////////////////////////////////////////////////////////
//
// Physical Entity header
//
// File: physicalentity.h
// Description : PhysicalEntity class declarations
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#ifndef physicalentity_h
#define physicalentity_h
#pragma once
enum phentity_flags_int {
pef_use_geom_callbacks = 0x2000000
};
struct geom {
phys_geometry *pPhysGeom,*pPhysGeomProxy;
int id;
vectorf pos;
quaternionf q;
float scale;
float mass;
int surface_idx;
unsigned int flags,flagsCollider;
float maxdim;
float minContactDist;
vectorf BBox[2];
};
class CPhysicalWorld;
class CRayGeom;
class CPhysicalEntity : public CPhysicalPlaceholder {
public:
CPhysicalEntity(CPhysicalWorld *pworld);
virtual ~CPhysicalEntity();
virtual pe_type GetType() { return PE_STATIC; }
int AddRef() { return ++m_nRefCount; }
int Release() { return --m_nRefCount; }
virtual int SetParams(pe_params*);
virtual int GetParams(pe_params*);
virtual int GetStatus(pe_status*);
virtual int Action(pe_action*);
virtual int AddGeometry(phys_geometry *pgeom, pe_geomparams* params,int id=-1);
virtual void RemoveGeometry(int id);
virtual void *GetForeignData(int itype=0) { return itype==m_iForeignData ? m_pForeignData:0; }
virtual int GetiForeignData() { return m_iForeignData; }
virtual IPhysicalWorld *GetWorld() { return (IPhysicalWorld*)m_pWorld; }
virtual CPhysicalEntity *GetEntity() { return this; }
virtual CPhysicalEntity *GetEntityFast() { return this; }
virtual void StartStep(float time_interval) {}
virtual float GetMaxTimeStep(float time_interval) { return time_interval; }
virtual float GetLastTimeStep(float time_interval) { return time_interval; }
virtual int Step(float time_interval) { return 1; }
virtual void StepBack(float time_interval) {}
virtual int GetContactCount(int nMaxPlaneContacts) { return 0; }
virtual int RegisterContacts(float time_interval,int nMaxPlaneContacts) { return 0; }
virtual int Update(float time_interval, float damping) { return 1; }
virtual float CalcEnergy(float time_interval) { return 0; }
virtual float GetDamping(float time_interval) { return 1.0f; }
virtual int AddCollider(CPhysicalEntity *pCollider);
virtual int RemoveCollider(CPhysicalEntity *pCollider, bool bAlwaysRemove=true);
virtual int RemoveContactPoint(CPhysicalEntity *pCollider, const vectorf &pt, float mindist2) { return -1; }
virtual int HasContactsWith(CPhysicalEntity *pent) { return 0; }
virtual int HasCollisionContactsWith(CPhysicalEntity *pent) { return 0; }
virtual void AlertNeighbourhoodND();
virtual int Awake(int bAwake=1,int iSource=0) { return 0; }
virtual int IsAwake(int ipart=-1) { return 0; }
int GetColliders(CPhysicalEntity **&pentlist) { pentlist=m_pColliders; return m_nColliders; }
virtual int RayTrace(CRayGeom *pRay, geom_contact *&pcontacts) { return 0; }
virtual void ApplyVolumetricPressure(const vectorf &epicenter, float kr, float rmin) {}
virtual RigidBody *GetRigidBody(int ipart=-1);
virtual void GetContactMatrix(const vectorf &pt, int ipart, matrix3x3f &K) {}
virtual void GetSpatialContactMatrix(const vectorf &pt, int ipart, float Ibuf[][6]) {}
virtual float GetMassInv() { return 0; }
virtual int IsPointInside(vectorf pt);
virtual void DrawHelperInformation(void (*DrawLineFunc)(float*,float*), int flags);
virtual void GetMemoryStatistics(ICrySizer *pSizer);
virtual int GetStateSnapshot(class CStream &stm, float time_back=0, int flags=0) { return 0; }
virtual int SetStateFromSnapshot(class CStream &stm, int flags=0) { return 0; }
virtual int PostSetStateFromSnapshot() { return 1; }
virtual unsigned int GetStateChecksum() { return 0; }
virtual int GetStateSnapshotTxt(char *txtbuf,int szbuf, float time_back=0);
virtual void SetStateFromSnapshotTxt(const char *txtbuf,int szbuf);
virtual void ComputeBBox();
int m_nRefCount;
unsigned int m_flags;
CPhysicalEntity *m_next,*m_prev;
CPhysicalWorld *m_pWorld;
int m_iPrevSimClass;
int m_iGroup,m_bMoved;
CPhysicalEntity *m_next_coll,*m_next_coll1;
vectorf m_pos;
quaternionf m_qrot;
CPhysicalEntity **m_pColliders;
int m_nColliders,m_nCollidersAlloc;
CPhysicalEntity *m_next_aux,*m_prev_aux;
CPhysicalEntity *m_pOuterEntity;
CGeometry *m_pBoundingGeometry;
int m_bProcessed_aux;
float m_timeIdle,m_maxTimeIdle;
int m_bPermanent;
geom *m_parts,m_defpart;
int m_nParts,m_nPartsAlloc;
int m_iLastIdx;
};
extern RigidBody g_StaticRigidBody;
extern CPhysicalEntity g_StaticPhysicalEntity;
#endif

View File

@@ -0,0 +1,190 @@
//////////////////////////////////////////////////////////////////////
//
// Physical Placeholder
//
// File: physicalplaceholder.cpp
// Description : PhysicalPlaceholder class implementation
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "bvtree.h"
#include "geometry.h"
#include "geoman.h"
#include "rigidbody.h"
#include "physicalplaceholder.h"
#include "physicalentity.h"
#include "physicalworld.h"
IPhysicalWorld *CPhysicalPlaceholder::GetWorld()
{
CPhysicalWorld *pWorld;
if (g_nPhysWorlds==1)
pWorld = g_pPhysWorlds[0];
else
for(int i=0;i<g_nPhysWorlds && !(pWorld=g_pPhysWorlds[i])->IsPlaceholder(this);i++);
return pWorld;
}
CPhysicalEntity *CPhysicalPlaceholder::GetEntity()
{
CPhysicalEntity *pEntBuddy;
if (!m_pEntBuddy) {
CPhysicalWorld *pWorld;
if (g_nPhysWorlds==1)
pWorld = g_pPhysWorlds[0];
else
for(int i=0;i<g_nPhysWorlds && !(pWorld=g_pPhysWorlds[i])->IsPlaceholder(this);i++);
if (pWorld->m_pPhysicsStreamer) {
pWorld->SetCurrentEntityHost(this);
pWorld->m_pPhysicsStreamer->CreatePhysicalEntity(m_pForeignData,m_iForeignData,m_iForeignFlags);
pWorld->SetCurrentEntityHost(0);
if (!m_pEntBuddy) {
pWorld->m_pLog->Log("\002Error: physical entity on-demand creation failed (type: %d, id: %d)",m_iForeignData,m_id);
pEntBuddy = pWorld->m_pHeightfield;
} else
pEntBuddy = (CPhysicalEntity*)m_pEntBuddy;
}
} else
pEntBuddy = (CPhysicalEntity*)m_pEntBuddy;
pEntBuddy->m_timeIdle = 0;
return pEntBuddy;
}
pe_type CPhysicalPlaceholder::GetType()
{
switch (m_iSimClass) {
case 0: return PE_STATIC;
case 1:case 2: return PE_RIGID;
case 3: return PE_LIVING;
case 4: return PE_PARTICLE;
default: return PE_NONE;
}
}
int CPhysicalPlaceholder::SetParams(pe_params *_params)
{
if (_params->type==pe_params_bbox::type_id) {
pe_params_bbox *params = (pe_params_bbox*)_params;
if (!is_unused(params->BBox[0])) m_BBox[0] = params->BBox[0];
if (!is_unused(params->BBox[1])) m_BBox[1] = params->BBox[1];
if (m_pEntBuddy) {
m_pEntBuddy->m_BBox[0] = m_BBox[0];
m_pEntBuddy->m_BBox[1] = m_BBox[1];
}
((CPhysicalWorld*)GetWorld())->RepositionEntity(this,1);
return 1;
}
if (_params->type==pe_params_pos::type_id) {
pe_params_pos *params = (pe_params_pos*)_params;
if (!is_unused(params->pos) | !is_unused(params->q) | !is_unused(params->scale) |
(intptr_t)params->pMtx3x3 | (intptr_t)params->pMtx3x3T | (intptr_t)params->pMtx4x4 | (intptr_t)params->pMtx4x4T)
return GetEntity()->SetParams(params);
if (!is_unused(params->iSimClass))
m_iSimClass = params->iSimClass;
return 1;
}
if (_params->type==pe_params_foreign_data::type_id) {
pe_params_foreign_data *params = (pe_params_foreign_data*)_params;
if (!is_unused(params->iForeignData)) m_iForeignData = params->iForeignData;
if (!is_unused(params->pForeignData)) m_pForeignData = params->pForeignData;
if (!is_unused(params->iForeignFlags)) m_iForeignFlags = params->iForeignFlags;
if (m_pEntBuddy) {
m_pEntBuddy->m_pForeignData = m_pForeignData;
m_pEntBuddy->m_iForeignData = m_iForeignData;
m_pEntBuddy->m_iForeignFlags = m_iForeignFlags;
}
return 1;
}
if (m_pEntBuddy)
return m_pEntBuddy->SetParams(_params);
return 0;//GetEntity()->SetParams(_params);
}
int CPhysicalPlaceholder::GetParams(pe_params *_params)
{
if (_params->type==pe_params_bbox::type_id) {
pe_params_bbox *params = (pe_params_bbox*)_params;
params->BBox[0] = m_BBox[0];
params->BBox[1] = m_BBox[1];
return 1;
}
if (_params->type==pe_params_foreign_data::type_id) {
pe_params_foreign_data *params = (pe_params_foreign_data*)_params;
params->iForeignData = m_iForeignData;
params->pForeignData = m_pForeignData;
params->iForeignFlags = m_iForeignFlags;
return 1;
}
return GetEntity()->GetParams(_params);
}
int CPhysicalPlaceholder::GetStatus(pe_status* _status)
{
if (_status->type==pe_status_placeholder::type_id) {
((pe_status_placeholder*)_status)->pFullEntity = m_pEntBuddy;
return 1;
}
if (_status->type==pe_status_awake::type_id)
return 0;
return GetEntity()->GetStatus(_status);
}
int CPhysicalPlaceholder::Action(pe_action* action) {
if (action->type==pe_action_awake::type_id && ((pe_action_awake*)action)->bAwake==0 && !m_pEntBuddy) {
if (m_iSimClass==2)
m_iSimClass = 1;
return 1;
}
return GetEntity()->Action(action);
}
int CPhysicalPlaceholder::AddGeometry(phys_geometry *pgeom, pe_geomparams* params,int id) {
return GetEntity()->AddGeometry(pgeom,params,id);
}
void CPhysicalPlaceholder::RemoveGeometry(int id) {
return GetEntity()->RemoveGeometry(id);
}
int CPhysicalPlaceholder::GetStateSnapshot(class CStream &stm, float time_back, int flags) {
return GetEntity()->GetStateSnapshot(stm,time_back,flags);
}
int CPhysicalPlaceholder::SetStateFromSnapshot(class CStream &stm, int flags) {
return GetEntity()->SetStateFromSnapshot(stm,flags);
}
int CPhysicalPlaceholder::PostSetStateFromSnapshot() {
return GetEntity()->PostSetStateFromSnapshot();
}
int CPhysicalPlaceholder::GetStateSnapshotTxt(char *txtbuf,int szbuf, float time_back) {
return GetEntity()->GetStateSnapshotTxt(txtbuf,szbuf,time_back);
}
void CPhysicalPlaceholder::SetStateFromSnapshotTxt(const char *txtbuf,int szbuf) {
GetEntity()->SetStateFromSnapshotTxt(txtbuf,szbuf);
}
unsigned int CPhysicalPlaceholder::GetStateChecksum() {
return GetEntity()->GetStateChecksum();
}
int CPhysicalPlaceholder::Step(float time_interval) {
return GetEntity()->Step(time_interval);
}
void CPhysicalPlaceholder::StartStep(float time_interval) {
GetEntity()->StartStep(time_interval);
}
void CPhysicalPlaceholder::StepBack(float time_interval) {
return GetEntity()->StepBack(time_interval);
}

View File

@@ -0,0 +1,76 @@
//////////////////////////////////////////////////////////////////////
//
// Physical Placeholder header
//
// File: physicalplaceholder.h
// Description : PhysicalPlaceholder class declarations
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#ifndef physicalplaceholder_h
#define physicalplaceholder_h
#pragma once
struct pe_gridthunk {
pe_gridthunk *next;
pe_gridthunk *prev;
class CPhysicalPlaceholder *pent;
};
class CPhysicalEntity;
class CPhysicalPlaceholder : public IPhysicalEntity {
public:
vectorf m_BBox[2];
void *m_pForeignData;
int m_iForeignData : 16;
int m_iForeignFlags : 16;
struct vec2dpacked {
int x : 16;
int y : 16;
};
vec2dpacked m_ig[2];
pe_gridthunk *m_pGridThunks;
int m_nGridThunks : 16;
int m_nGridThunksAlloc : 16;
CPhysicalPlaceholder *m_pEntBuddy;
unsigned int m_bProcessed : 1;
int m_id : 23;
int m_iSimClass : 8;
virtual CPhysicalEntity *GetEntity();
virtual CPhysicalEntity *GetEntityFast() { return (CPhysicalEntity*)m_pEntBuddy; }
virtual pe_type GetType();
virtual int SetParams(pe_params* params);
virtual int GetParams(pe_params* params);
virtual int GetStatus(pe_status* status);
virtual int Action(pe_action* action);
virtual int AddGeometry(phys_geometry *pgeom, pe_geomparams* params,int id=-1);
virtual void RemoveGeometry(int id);
virtual void *GetForeignData(int itype=0) { return m_iForeignData==itype ? m_pForeignData : 0; }
virtual int GetiForeignData() { return m_iForeignData; }
virtual int GetStateSnapshot(class CStream &stm, float time_back=0, int flags=0);
virtual int SetStateFromSnapshot(class CStream &stm, int flags=0);
virtual int PostSetStateFromSnapshot();
virtual int GetStateSnapshotTxt(char *txtbuf,int szbuf, float time_back=0);
virtual void SetStateFromSnapshotTxt(const char *txtbuf,int szbuf);
virtual unsigned int GetStateChecksum();
virtual void StartStep(float time_interval);
virtual int Step(float time_interval);
virtual void StepBack(float time_interval);
virtual IPhysicalWorld *GetWorld();
virtual void GetMemoryStatistics(ICrySizer *pSizer) {};
};
#endif

1776
CryPhysics/physicalworld.cpp Normal file

File diff suppressed because it is too large Load Diff

197
CryPhysics/physicalworld.h Normal file
View File

@@ -0,0 +1,197 @@
//////////////////////////////////////////////////////////////////////
//
// Physical Entity header
//
// File: physicalentity.h
// Description : PhysicalEntity and PhysicalWorld classes declarations
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#ifndef physicalworld_h
#define physicalworld_h
#pragma once
const int NSURFACETYPES = 2048;
const int PLACEHOLDER_CHUNK_SZLG2 = 8;
const int PLACEHOLDER_CHUNK_SZ = 1<<PLACEHOLDER_CHUNK_SZLG2;
class CPhysicalPlaceholder;
class CPhysicalEntity;
struct pe_gridthunk;
enum { pef_step_requested = 0x10000000 };
class CPhysicalWorld : public IPhysicalWorld, public IPhysUtils, public CGeomManager {
public:
CPhysicalWorld(ILog *pLog);
~CPhysicalWorld();
virtual void Init();
virtual void Shutdown(int bDeleteEntities = 1);
virtual void Release() { delete this; }
virtual IGeomManager* GetGeomManager() { return this; }
virtual IPhysUtils* GetPhysUtils() { return this; }
virtual void SetupEntityGrid(int axisz, vectorf org, int nx,int ny, float stepx,float stepy);
virtual void SetHeightfieldData(const heightfield *phf);
virtual int GetHeightfieldData(heightfield *phf);
virtual int SetSurfaceParameters(int surface_idx, float bounciness,float friction, unsigned int flags=0);
virtual int GetSurfaceParameters(int surface_idx, float &bounciness,float &friction, unsigned int &flags);
virtual PhysicsVars *GetPhysVars() { return &m_vars; }
virtual IPhysicalEntity* CreatePhysicalEntity(pe_type type, pe_params* params=0, void *pForeignData=0,int iForeignData=0, int id=-1)
{ return CreatePhysicalEntity(type,0.0f,params,pForeignData,iForeignData,id); }
virtual IPhysicalEntity* CreatePhysicalEntity(pe_type type, float lifeTime, pe_params* params=0, void *pForeignData=0,int iForeignData=0,
int id=-1,IPhysicalEntity *pHostPlaceholder=0);
virtual IPhysicalEntity *CreatePhysicalPlaceholder(pe_type type, pe_params* params=0, void *pForeignData=0,int iForeignData=0, int id=-1);
virtual int DestroyPhysicalEntity(IPhysicalEntity *pent, int mode=0);
virtual int SetPhysicalEntityId(IPhysicalEntity *pent, int id, int bReplace=1);
virtual int GetPhysicalEntityId(IPhysicalEntity *pent);
virtual IPhysicalEntity* GetPhysicalEntityById(int id);
int IsPlaceholder(CPhysicalPlaceholder *pent) {
if (!pent) return 0;
int iChunk; for(iChunk=0; iChunk<m_nPlaceholderChunks && (unsigned int)(pent-m_pPlaceholders[iChunk])>=(unsigned int)PLACEHOLDER_CHUNK_SZ; iChunk++);
return iChunk<m_nPlaceholderChunks ? (iChunk<<PLACEHOLDER_CHUNK_SZLG2 | pent-m_pPlaceholders[iChunk])+1 : 0;
}
void SetCurrentEntityHost(CPhysicalPlaceholder *pHost) { m_pCurEntityHost=pHost; }
virtual void TimeStep(float time_interval, int flags=ent_all|ent_deleted);
virtual float GetPhysicsTime() { return m_timePhysics; }
virtual int GetiPhysicsTime() { return m_iTimePhysics; }
virtual void SetPhysicsTime(float time) {
m_timePhysics = time;
if (m_vars.timeGranularity>0)
m_iTimePhysics = (int)(m_timePhysics/m_vars.timeGranularity+0.5f);
}
virtual void SetiPhysicsTime(int itime) { m_timePhysics = (m_iTimePhysics=itime)*m_vars.timeGranularity; }
virtual void SetSnapshotTime(float time_snapshot,int iType=0) {
m_timeSnapshot[iType] = time_snapshot;
if (m_vars.timeGranularity>0)
m_iTimeSnapshot[iType] = (int)(time_snapshot/m_vars.timeGranularity+0.5f);
}
virtual void SetiSnapshotTime(int itime_snapshot,int iType=0) {
m_iTimeSnapshot[iType] = itime_snapshot; m_timeSnapshot[iType] = itime_snapshot*m_vars.timeGranularity;
}
virtual int RayWorldIntersection(vectorf org,vectorf dir, int objtypes, unsigned int flags, ray_hit *hits,int nmaxhits,
IPhysicalEntity *pSkipEnt=0,IPhysicalEntity *pSkipEntAux=0);
virtual void SimulateExplosion(vectorf epicenter,vectorf epicenterImp, float rmin,float rmax, float r,float impulsive_pressure_at_r,
int nOccRes=0,int nGrow=0,float rmin_occ=0.1f, IPhysicalEntity **pSkipEnts=0,int nSkipEnts=0,
int iTypes=ent_rigid|ent_sleeping_rigid|ent_living|ent_independent);
virtual float IsAffectedByExplosion(IPhysicalEntity *pent);
virtual void ResetDynamicEntities();
virtual void DestroyDynamicEntities();
virtual void PurgeDeletedEntities();
virtual void DrawPhysicsHelperInformation(void (*DrawLineFunc)(float*,float*));
virtual void GetMemoryStatistics(ICrySizer *pSizer);
virtual int CollideEntityWithBeam(IPhysicalEntity *_pent, vectorf org,vectorf dir,float r, ray_hit *phit);
virtual int RayTraceEntity(IPhysicalEntity *pient, vectorf origin,vectorf dir, ray_hit *pHit, pe_params_pos *pp=0);
virtual int GetEntitiesInBox(vectorf ptmin,vectorf ptmax, IPhysicalEntity **&pList, int objtypes) {
return GetEntitiesAround(ptmin,ptmax, (CPhysicalEntity**&)pList, objtypes);
}
int GetEntitiesAround(const vectorf &ptmin,const vectorf &ptmax, CPhysicalEntity **&pList, int objtypes, CPhysicalEntity *pPetitioner=0);
void RepositionEntity(CPhysicalPlaceholder *pobj, int flags=3);
void DetachEntityGridThunks(CPhysicalPlaceholder *pobj);
void ScheduleForStep(CPhysicalEntity *pent);
CPhysicalEntity *CheckColliderListsIntegrity();
virtual int BreakPolygon(vector2df *ptSrc,int nPt, int nCellx,int nCelly, int maxPatchTris, vector2df *&ptout,int *&nPtOut,
float jointhresh=0.5f,int seed=-1)
{ return ::BreakPolygon(ptSrc,nPt, nCellx,nCelly, maxPatchTris, ptout,nPtOut, jointhresh,seed); };
virtual int CoverPolygonWithCircles(strided_pointer<vector2df> pt,int npt,bool bConsecutive, const vector2df &center,
vector2df *&centers,float *&radii, float minCircleRadius)
{ return ::CoverPolygonWithCircles(pt,npt,bConsecutive, center, centers,radii, minCircleRadius); }
virtual void DeletePointer(void *pdata) { if (pdata) delete[] pdata; }
virtual void SetPhysicsStreamer(IPhysicsStreamer *pStreamer) { m_pPhysicsStreamer=pStreamer; }
virtual void SetPhysicsEventClient(IPhysicsEventClient *pEventClient) { m_pEventClient=pEventClient; }
virtual float GetLastEntityUpdateTime(IPhysicalEntity *pent) { return m_updateTimes[((CPhysicalPlaceholder*)pent)->m_iSimClass & 7]; }
void AddEntityProfileInfo(CPhysicalEntity *pent,int nTicks);
virtual int GetEntityProfileInfo(phys_profile_info *&pList);
virtual int SerializeWorld(const char *fname, int bSave);
virtual int SerializeGeometries(const char *fname, int bSave);
PhysicsVars m_vars;
ILog *m_pLog;
IPhysicsStreamer *m_pPhysicsStreamer;
IPhysicsEventClient *m_pEventClient;
CPhysicalEntity *m_pTypedEnts[8],*m_pTypedEntsPerm[8];
CPhysicalEntity **m_pTmpEntList,**m_pTmpEntList1;
float *m_pGroupMass,*m_pMassList;
int *m_pGroupIds,*m_pGroupNums;
grid m_entgrid;
int m_iEntAxisz;
pe_gridthunk **m_pEntGrid;
int m_nEnts,m_nEntsAlloc;
int m_nDynamicEntitiesDeleted;
CPhysicalPlaceholder **m_pEntsById;
int m_nIdsAlloc, m_iNextId;
int m_bGridThunksChanged;
int m_bUpdateOnlyFlagged;
int m_nPlaceholders,m_nPlaceholderChunks,m_iLastPlaceholder;
CPhysicalPlaceholder **m_pPlaceholders;
int *m_pPlaceholderMap;
CPhysicalPlaceholder *m_pCurEntityHost;
CPhysicalEntity *m_pEntBeingDeleted;
int *m_pGridStat[6],*m_pGridDyn[6];
int m_nOccRes;
vectorf m_lastEpicenter;
float m_lastRmax;
CPhysicalEntity **m_pExplVictims;
float *m_pExplVictimsFrac;
int m_nExplVictims,m_nExplVictimsAlloc;
CPhysicalEntity *m_pHeightfield;
matrix3x3f m_HeightfieldBasis;
vectorf m_HeightfieldOrigin;
float m_timePhysics,m_timeSurplus,m_timeSnapshot[4];
int m_iTimePhysics,m_iTimeSnapshot[4];
float m_updateTimes[8];
int m_iSubstep,m_bWorldStep,m_iCurGroup;
CPhysicalEntity *m_pAuxStepEnt;
phys_profile_info m_pEntProfileData[16];
int m_nProfiledEnts;
float m_BouncinessTable[NSURFACETYPES];
float m_FrictionTable[NSURFACETYPES];
float m_DynFrictionTable[NSURFACETYPES];
unsigned int m_SurfaceFlagsTable[NSURFACETYPES];
};
extern int g_nPhysWorlds;
extern CPhysicalWorld *g_pPhysWorlds[];
#ifdef ENTITY_PROFILER_ENABLED
#define PHYS_ENTITY_PROFILER CPhysEntityProfiler ent_profiler(this);
#else
#define PHYS_ENTITY_PROFILER
#endif
struct CPhysEntityProfiler {
int64 m_iStartTime;
CPhysicalEntity *m_pEntity;
CPhysEntityProfiler(CPhysicalEntity *pent) {
m_pEntity = pent;
m_iStartTime = GetTicks();
}
~CPhysEntityProfiler() {
if (m_pEntity->m_pWorld->m_vars.bProfileEntities)
m_pEntity->m_pWorld->AddEntityProfileInfo(m_pEntity,GetTicks()-m_iStartTime);
}
};
#endif

379
CryPhysics/polynomial.h Normal file
View File

@@ -0,0 +1,379 @@
#ifndef polynomial_h
#define polynomial_h
#pragma once
template<class ftype,int degree> class polynomial_tpl {
public:
explicit polynomial_tpl() { denom=(ftype)1; };
explicit polynomial_tpl(ftype op) { zero(); data[degree]=op; }
polynomial_tpl& zero() {
for(int i=0;i<=degree;i++) data[i]=0;
denom=(ftype)1; return *this;
}
polynomial_tpl(const polynomial_tpl<ftype,degree>& src) { *this=src; }
polynomial_tpl& operator=(const polynomial_tpl<ftype,degree> &src) {
denom=src.denom; for(int i=0;i<=degree;i++) data[i]=src.data[i];
return *this;
}
template<int degree1> polynomial_tpl& operator=(const polynomial_tpl<ftype,degree1> &src) {
int i; denom = src.denom;
for(i=0;i<=min(degree,degree1);i++) data[i] = src.data[i];
for(;i<degree;i++) data[i]=0;
return *this;
}
polynomial_tpl& set(ftype *pdata) {
for(int i=0;i<=degree;i++) data[degree-i]=pdata[i];
return *this;
}
ftype &operator[](int idx) { return data[idx]; }
void calc_deriviative(polynomial_tpl<ftype,degree> &deriv,int curdegree=degree) const;
polynomial_tpl& fixsign() {
ftype sg = sgnnz(denom); denom *= sg;
for(int i=0;i<=degree;i++) data[i]*=sg;
return *this;
}
int findroots(ftype start,ftype end, ftype *proots, int nIters=20,int curdegree=degree) const;
int nroots(ftype start,ftype end) const;
ftype eval(ftype x) const {
ftype res=0;
for(int i=degree;i>=0;i--) res = res*x+data[i];
return res;
}
ftype eval(ftype x,int subdegree) const {
ftype res = data[subdegree];
for(int i=subdegree-1;i>=0;i--) res = res*x+data[i];
return res;
}
polynomial_tpl& operator+=(ftype op) { data[0] += op*denom; return *this; }
polynomial_tpl& operator-=(ftype op) { data[0] -= op*denom; return *this; }
polynomial_tpl operator*(ftype op) const {
polynomial_tpl<ftype,degree> res; res.denom = denom;
for(int i=0;i<=degree;i++) res.data[i] = data[i]*op;
return res;
}
polynomial_tpl& operator*=(ftype op) {
for(int i=0;i<=degree;i++) data[i]*=op;
return *this;
}
polynomial_tpl operator/(ftype op) const {
polynomial_tpl<ftype,degree> res = *this;
res.denom = denom*op;
return res;
}
polynomial_tpl& operator/=(ftype op) { denom *= op; return *this; }
polynomial_tpl<ftype,degree*2> sqr() const { return *this**this; }
ftype denom;
ftype data[degree+1];
};
template <class ftype>
struct tagPolyE
{
inline static ftype polye() {return (ftype)1E-10;}
};
inline float tagPolyE<float>::polye() {return 1e-6f;}
template <class ftype> inline ftype polye() { return tagPolyE<ftype>::polye(); }
#define degmax(degree1,degree2) degree1-(degree1-degree2&(degree1-degree2)>>31)
template<class ftype,int degree> polynomial_tpl<ftype,degree> operator+(const polynomial_tpl<ftype,degree> &pn, ftype op) {
polynomial_tpl<ftype,degree> res = pn;
res.data[0] += op*res.denom;
return res;
}
template<class ftype,int degree> polynomial_tpl<ftype,degree> operator-(const polynomial_tpl<ftype,degree> &pn, ftype op) {
polynomial_tpl<ftype,degree> res = pn;
res.data[0] -= op*res.denom;
return res;
}
template<class ftype,int degree> polynomial_tpl<ftype,degree> operator+(ftype op, const polynomial_tpl<ftype,degree> &pn) {
polynomial_tpl<ftype,degree> res = pn;
res.data[0] += op*res.denom;
return res;
}
template<class ftype,int degree> polynomial_tpl<ftype,degree> operator-(ftype op, const polynomial_tpl<ftype,degree> &pn) {
polynomial_tpl<ftype,degree> res = pn;
res.data[0] -= op*res.denom;
for(int i=0;i<=degree;i++) res.data[i]=-res.data[i];
return res;
}
template<class ftype,int degree>
polynomial_tpl<ftype,degree*2> psqr(const polynomial_tpl<ftype,degree> &op) { return op*op; }
template <class ftype,int degree1,int degree2>
polynomial_tpl<ftype,degmax(degree1,degree2)> operator+(const polynomial_tpl<ftype,degree1> &op1, const polynomial_tpl<ftype,degree2> &op2) {
polynomial_tpl<ftype,degmax(degree1,degree2)> res; int i;
for(i=0;i<=min(degree1,degree2);i++) res.data[i] = op1.data[i]*op2.denom+op2.data[i]*op1.denom;
for(;i<=degree1;i++) res.data[i] = op1.data[i]*op2.denom;
for(;i<=degree2;i++) res.data[i] = op2.data[i]*op1.denom;
res.denom = op1.denom*op2.denom;
return res;
}
template <class ftype,int degree1,int degree2>
polynomial_tpl<ftype,degmax(degree1,degree2)> operator-(const polynomial_tpl<ftype,degree1> &op1, const polynomial_tpl<ftype,degree2> &op2) {
polynomial_tpl<ftype,degmax(degree1,degree2)> res; int i;
for(i=0;i<=min(degree1,degree2);i++) res.data[i] = op1.data[i]*op2.denom-op2.data[i]*op1.denom;
for(;i<=degree1;i++) res.data[i] = op1.data[i]*op2.denom;
for(;i<=degree2;i++) res.data[i] = op2.data[i]*op1.denom;
res.denom = op1.denom*op2.denom;
return res;
}
template <class ftype,int degree1,int degree2>
polynomial_tpl<ftype,degree1>& operator+=(polynomial_tpl<ftype,degree1> &op1, const polynomial_tpl<ftype,degree2> &op2) {
for(int i=0;i<min(degree1,degree2);i++) op1.data[i] = op1.data[i]*op2.denom + op2.data[i]*op1.denom;
op1.denom *= op2.denom;
return op1;
}
template <class ftype,int degree1,int degree2>
polynomial_tpl<ftype,degree1>& operator-=(polynomial_tpl<ftype,degree1> &op1, const polynomial_tpl<ftype,degree2> &op2) {
for(int i=0;i<min(degree1,degree2);i++) op1.data[i] = op1.data[i]*op2.denom - op2.data[i]*op1.denom;
op1.denom *= op2.denom;
return op1;
}
template <class ftype,int degree1,int degree2>
polynomial_tpl<ftype,degree1+degree2> operator*(const polynomial_tpl<ftype,degree1> &op1, const polynomial_tpl<ftype,degree2> &op2)
{
polynomial_tpl<ftype,degree1+degree2> res; res.zero();
int j;
switch (degree1) {
case 8: for(j=0;j<=degree2;j++) res.data[8+j] += op1.data[8]*op2.data[j];
case 7: for(j=0;j<=degree2;j++) res.data[7+j] += op1.data[7]*op2.data[j];
case 6: for(j=0;j<=degree2;j++) res.data[6+j] += op1.data[6]*op2.data[j];
case 5: for(j=0;j<=degree2;j++) res.data[5+j] += op1.data[5]*op2.data[j];
case 4: for(j=0;j<=degree2;j++) res.data[4+j] += op1.data[4]*op2.data[j];
case 3: for(j=0;j<=degree2;j++) res.data[3+j] += op1.data[3]*op2.data[j];
case 2: for(j=0;j<=degree2;j++) res.data[2+j] += op1.data[2]*op2.data[j];
case 1: for(j=0;j<=degree2;j++) res.data[1+j] += op1.data[1]*op2.data[j];
case 0: for(j=0;j<=degree2;j++) res.data[0+j] += op1.data[0]*op2.data[j];
}
res.denom = op1.denom*op2.denom;
return res;
}
template <class ftype>
void polynomial_divide(const polynomial_tpl<ftype,8> &num, const polynomial_tpl<ftype,8> &den, polynomial_tpl<ftype,8> &quot,
polynomial_tpl<ftype,8> &rem, int degree1,int degree2)
{
int i,j,k,l; ftype maxel;
for(i=0;i<=degree1;i++) rem.data[i] = num.data[i];
for(i=0;i<=degree1-degree2;i++) quot.data[i] = 0;
for(i=1,maxel=fabs_tpl(num.data[0]); i<=degree1; i++) maxel = max(maxel,num.data[i]);
for(maxel*=polye<ftype>(); degree1>=0 && fabs_tpl(num.data[degree1])<maxel; degree1--);
for(i=1,maxel=fabs_tpl(den.data[0]); i<=degree1; i++) maxel = max(maxel,den.data[i]);
for(maxel*=polye<ftype>(); degree2>=0 && fabs_tpl(den.data[degree2])<maxel; degree2--);
rem.denom = num.denom;
quot.denom = (ftype)1;
if (degree1<0 || degree2<0)
return;
for(k=degree1-degree2,l=degree1; l>=degree2; l--,k--) {
quot.data[k] = rem.data[l]*den.denom; quot.denom *= den.data[degree2];
for(i=degree1-degree2; i>k; i--) quot.data[i] *= den.data[degree2];
for(i=degree2-1,j=l-1; i>=0; i--,j--)
rem.data[j] = rem.data[j]*den.data[degree2] - den.data[i]*rem.data[l];
for(; j>=0; j--) rem.data[j] *= den.data[degree2];
rem.denom *= den.data[degree2];
}
}
template <class ftype,int degree1,int degree2>
polynomial_tpl<ftype,degree1-degree2> operator/(const polynomial_tpl<ftype,degree1> &num, const polynomial_tpl<ftype,degree2> &den) {
polynomial_tpl<ftype,degree1-degree2> quot;
polynomial_tpl<ftype,degree1> rem;
polynomial_divide((polynomial_tpl<ftype,8>&)num,(polynomial_tpl<ftype,8>&)den, (polynomial_tpl<ftype,8>&)quot,
(polynomial_tpl<ftype,8>&)rem, degree1,degree2);
return quot;
}
template <class ftype,int degree1,int degree2>
polynomial_tpl<ftype,degree2-1> operator%(const polynomial_tpl<ftype,degree1> &num, const polynomial_tpl<ftype,degree2> &den) {
polynomial_tpl<ftype,degree1-degree2> quot;
polynomial_tpl<ftype,degree1> rem;
polynomial_divide((polynomial_tpl<ftype,8>&)num,(polynomial_tpl<ftype,8>&)den, (polynomial_tpl<ftype,8>&)quot,
(polynomial_tpl<ftype,8>&)rem, degree1,degree2);
return (polynomial_tpl<ftype,degree2-1>&)rem;
}
template <class ftype,int degree>
void polynomial_tpl<ftype,degree>::calc_deriviative(polynomial_tpl<ftype,degree> &deriv, int curdegree) const {
for(int i=0; i<curdegree; i++)
deriv.data[i] = data[i+1]*(i+1);
deriv.denom = denom;
}
template <class ftype,int degree>
int polynomial_tpl<ftype,degree>::nroots(ftype start,ftype end) const
{
polynomial_tpl<ftype,degree> f[degree+1];
int i,j,sg_a,sg_b;
ftype val,prevval;
calc_deriviative(f[0]);
polynomial_divide((polynomial_tpl<ftype,8>&)*this,(polynomial_tpl<ftype,8>&)f[0], (polynomial_tpl<ftype,8>&)f[degree],
(polynomial_tpl<ftype,8>&)f[1], degree,degree-1);
f[1].denom = -f[1].denom;
for(i=2;i<degree;i++) {
polynomial_divide((polynomial_tpl<ftype,8>&)f[i-2],(polynomial_tpl<ftype,8>&)f[i-1], (polynomial_tpl<ftype,8>&)f[degree],
(polynomial_tpl<ftype,8>&)f[i], degree+1-i,degree-i);
f[i].denom = -f[i].denom;
if (fabs_tpl(f[i].denom)>(ftype)1E10) {
for(j=0;j<=degree-1-i;j++) f[i].data[j] *= (ftype)1E-10;
f[i].denom *= (ftype)1E-10;
}
}
prevval = eval(start)*denom;
for(i=sg_a=0; i<degree; i++,prevval=val) {
val = f[i].eval(start,degree-1-i)*f[i].denom;
sg_a += isneg(val*prevval);
}
prevval = eval(end)*denom;
for(i=sg_b=0; i<degree; i++,prevval=val) {
val = f[i].eval(end,degree-1-i)*f[i].denom;
sg_b += isneg(val*prevval);
}
return fabs_tpl(sg_a-sg_b);
}
template<class ftype> inline ftype cubert_tpl(ftype x) { return fabs_tpl(x)>1E-20 ? exp_tpl(log_tpl(fabs_tpl(x))*(ftype)(1.0/3))*sgnnz(x) : x; }
template<class ftype> inline ftype pow_tpl(ftype x,ftype pow) { return fabs_tpl(x)>1E-20 ? exp_tpl(log_tpl(fabs_tpl(x))*pow)*sgnnz(x) : x; }
template<class ftype> inline void swap(ftype *ptr,int i,int j) { ftype t=ptr[i]; ptr[i]=ptr[j]; ptr[j]=t; }
template <class ftype,int maxdegree>
int polynomial_tpl<ftype,maxdegree>::findroots(ftype start,ftype end, ftype *proots,int nIters,int degree) const
{
int i,j,nRoots=0; ftype maxel;
for(i=1,maxel=fabs_tpl(data[0]); i<=degree; i++) maxel = max(maxel,data[i]);
for(maxel*=polye<ftype>(); degree>0 && fabs_tpl(data[degree])<maxel; degree--);
if (degree==1) {
proots[0] = data[0]/data[1];
nRoots = 1;
} else if (degree==2) {
ftype a,b,c,d,bound[2],sg;
a=data[2]; b=data[1]; c=data[0]; d=sgnnz(a);
a*=d; b*=d; c*=d; d=b*b-a*c*4;
bound[0]=start*a*2+b; bound[1]=end*a*2+b; sg=sgnnz(bound[0]*bound[1]);
bound[0]*=bound[0]; bound[1]*=bound[1];
bound[isneg(fabs_tpl(end)-fabs_tpl(start))] *= sg;
if (isnonneg(d) & inrange(d,bound[0],bound[1])) {
d = sqrt_tpl(d); a = (ftype)0.5/a;
proots[nRoots] = (-b-d)*a; nRoots += inrange(proots[nRoots], start,end);
proots[nRoots] = (-b+d)*a; nRoots += inrange(proots[nRoots], start,end);
}
} else if (degree==3) {
real t,a,b,c,a3,p,q,Q,Qr,Ar,Ai,phi;
t = (ftype)1.0/data[3]; a = data[2]*t; b = data[1]*t; c = data[0]*t; a3 = a*(ftype)(1.0/3);
p = b-a*a3; q = (a3*b-c)*(ftype)0.5-cube(a3);
Q = cube(p*(ftype)(1.0/3)) + q*q;
Qr = sqrt_tpl(fabs_tpl(Q));
if (Q>0) {
proots[0] = cubert_tpl(q+Qr)+cubert_tpl(q-Qr) - a3;
nRoots = 1;
} else {
phi = atan2_tpl(Qr,q)*(ftype)(1.0/3);
t = pow_tpl(Qr*Qr+q*q,(ftype)(1.0/6));
Ar = t*cos_tpl(phi); Ai = t*sin_tpl(phi);
proots[0] = 2*Ar - a3;
proots[1] = -Ar + Ai*sqrt3 - a3;
proots[2] = -Ar - Ai*sqrt3 - a3;
i = idxmax3(proots); swap(proots,i,2);
i = isneg(proots[0]-proots[1]); swap(proots,i,1);
nRoots = 3;
}
} else if (degree==4) {
ftype t,a3,a2,a1,a0,y,R,D,E,subroots[3];
const ftype e = 1E-9;
t=(ftype)1.0/data[4]; a3=data[3]*t; a2=data[2]*t; a1=data[1]*t; a0=data[0]*t;
polynomial_tpl<ftype,3> p3aux; ftype kp3aux[]={ 1, -a2, a1*a3-4*a0, 4*a2*a0-a1*a1-a3*a3*a0 }; p3aux.set(kp3aux);
p3aux.findroots(-1E10,1E10,subroots); y=subroots[0];
R = a3*a3*(ftype)0.25-a2+y;
if (R>-e) {
if (R<e) {
D = E = a3*a3*(ftype)(3.0/4)-2*a2; t = y*y-4*a0;
if (t<-e)
return 0;
t = 2*sqrt_tpl(max((ftype)0,t));
} else {
R = sqrt_tpl(max((ftype)0,R));
D = E = a3*a3*(ftype)(3.0/4)-R*R-2*a2;
t = (4*a3*a2-8*a1-a3*a3*a3)/R*(ftype)0.25;
}
if (D+t>-e) {
D = sqrt_tpl(max((ftype)0,D+t));
proots[nRoots++] = a3*(ftype)-0.25+(R-D)*(ftype)0.5;
proots[nRoots++] = a3*(ftype)-0.25+(R+D)*(ftype)0.5;
}
if (E-t>-e) {
E = sqrt_tpl(max((ftype)0,E-t));
proots[nRoots++] = a3*(ftype)-0.25-(R+E)*(ftype)0.5;
proots[nRoots++] = a3*(ftype)-0.25-(R-E)*(ftype)0.5;
}
if (nRoots==4) {
i = idxmax3(proots); if (proots[3]<proots[i]) swap(proots,i,3);
i = idxmax3(proots); swap(proots,i,2);
i = isneg(proots[0]-proots[1]); swap(proots,i,1);
}
}
} else if (degree>4) {
ftype roots[maxdegree+1],prevroot,val,prevval[2],curval,bound[2],middle;
polynomial_tpl<ftype,maxdegree> deriv;
int nExtremes,iter,iBound;
calc_deriviative(deriv);
// find a subset of deriviative extremes between start and end
for(nExtremes=deriv.findroots(start,end,roots+1,nIters,degree-1)+1; nExtremes>1 && roots[nExtremes-1]>end; nExtremes--);
for(i=1;i<nExtremes && roots[i]<start;i++);
roots[i-1] = start; roots[nExtremes++] = end;
for(prevroot=start,prevval[0]=eval(start,degree),nRoots=0; i<nExtremes; prevval[0]=val,prevroot=roots[i++]) {
val = eval(roots[i],degree);
if (val*prevval[0]<0) {
// we have exactly one root between prevroot and roots[i]
bound[0]=prevroot; bound[1]=roots[i]; iter=0;
do {
middle = (bound[0]+bound[1])*(ftype)0.5;
curval = eval(middle,degree);
iBound = isneg(prevval[0]*curval);
bound[iBound] = middle;
prevval[iBound] = curval;
} while(++iter<nIters);
proots[nRoots++] = middle;
}
}
}
for(i=0; i<nRoots && proots[i]<start;i++);
for(; nRoots>i && proots[nRoots-1]>end;nRoots--);
for(j=i;j<nRoots;j++) proots[j-i] = proots[j];
return nRoots-i;
}
typedef polynomial_tpl<real,2> P2;
typedef polynomial_tpl<real,1> P1;
typedef polynomial_tpl<float,2> P2f;
typedef polynomial_tpl<float,1> P1f;
#endif

506
CryPhysics/qhull.cpp Normal file
View File

@@ -0,0 +1,506 @@
//////////////////////////////////////////////////////////////////////
//
// Quick Hull
//
// File: qhull.cpp
// Description : Quick Hull algorithm implementation
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "utils.h"
///////////////////////////// Qhull 3d ///////////////////////////////
struct ptitem {
ptitem *next,*prev;
};
struct qhtritem {
qhtritem *next,*prev;
ptitem *ptassoc;
vectorf n;
float d;
int idx[3];
qhtritem *buddy[3];
int deleted;
};
inline void relocate_ptritem(qhtritem *&ptr,intptr_t diff) {
ptr = (qhtritem*)((intptr_t)ptr+diff & ~-iszero((intptr_t)ptr)); // offset the pointer, but leave out 0s
}
inline void relocate_tritem(qhtritem *ptr,int diff) {
relocate_ptritem(ptr->next,diff); relocate_ptritem(ptr->prev,diff);
relocate_ptritem(ptr->buddy[0],diff); relocate_ptritem(ptr->buddy[1],diff); relocate_ptritem(ptr->buddy[2],diff);
}
template<class item> void delete_item_from_list(item *p) {
if (p->prev) p->prev->next = p->next;
if (p->next) p->next->prev = p->prev;
p->prev = p->next = 0;
}
template<class item> void add_item_to_list(item *&pin, item *pnew) {
if (!pin) pin=pnew->next=pnew->prev=pnew;
else {
pnew->next = pin->next; pnew->prev = pin;
pin->next->prev = pnew; pin->next = pnew;
}
}
template<class item> void merge_lists(item *&plist, item *pnew) {
if (!pnew) return;
if (!plist) plist = pnew;
else {
plist->next->prev = pnew->prev;
pnew->prev->next = plist->next;
plist->next = pnew;
pnew->prev = plist;
}
}
void associate_ptlist_with_trilist(ptitem *ptlist, qhtritem *trilist, ptitem *pt0,strided_pointer<vectorf> pvtx, float e) {
if (!ptlist) return;
ptitem *pt=ptlist,*ptnext,*ptlast=ptlist->prev;
qhtritem *tr; int i;
do {
ptnext = pt->next;
delete_item_from_list(pt);
tr=trilist; i=pt-pt0; do {
if (pvtx[i]*tr->n > tr->d+e) {
add_item_to_list(tr->ptassoc, pt);
break;
}
tr=tr->next;
} while(tr!=trilist);
if (pt==ptlast) break;
pt = ptnext;
} while(true);
}
static inline void swap(int *v,void **p, int i1,int i2)
{
int ti=v[i1]; v[i1]=v[i2]; v[i2]=ti;
void *tp=p[i1]; p[i1]=p[i2]; p[i2]=tp;
}
static void qsort(int *v,void **p, int left,int right)
{
if (left>=right) return;
int i,last;
swap(v,p, left, left+right>>1);
for(last=left,i=left+1; i<=right; i++)
if (v[i] < v[left])
swap(v,p, ++last, i);
swap(v,p, left,last);
qsort(v,p, left,last-1);
qsort(v,p, last+1,right);
}
static int bin_search(int *v,int n,int idx)
{
int left=0,right=n,m;
do {
m = left+right>>1;
if (v[m]==idx) return m;
if (v[m]<idx) left=m;
else right=m;
} while (left<right-1);
return left;
}
int __qhullcalled=0;
int qhull(strided_pointer<vectorf> pts, int npts, index_t*& pTris)
{
static ptitem ptbuf[1024];
static qhtritem trbuf[1024];
static qhtritem *tmparr_ptr_buf[512];
static int tmparr_idx_buf[512];
int iter=0,maxiter=0;
__qhullcalled++;
ptitem *pt,*ptmax,*ptdeleted,*ptlist = npts>sizeof(ptbuf)/sizeof(ptbuf[0]) ? new ptitem[npts] : ptbuf;
qhtritem *tr,*trnext,*trend,*trnew,*trdata=trbuf,*trstart=0,*trlast,*trbest;
int i,j,k,ti,trdatasz=sizeof(trbuf)/sizeof(trbuf[0]), bidx[6],n,next_iter,delbuds;
qhtritem **tmparr_ptr=tmparr_ptr_buf;
int *tmparr_idx=tmparr_idx_buf, tmparr_sz=512;
float dist,maxdist,e;
if (npts<=4) {
pTris = new index_t[6];
pTris[0]=0; pTris[1]=min(1,npts-1); pTris[2]=min(2,npts-1);
pTris[3]=0; pTris[4]=min(1,npts-1); pTris[5]=min(4,npts-1);
return 2;
}
vectorf pmin(MAX),pmax(MIN);
// select points for initial tetrahedron
// first, find 6 points corresponding to min and max coordinates
for(i=1;i<npts;i++) {
if (pts[i].x>pmax.x) { pmax.x=pts[i].x; bidx[0]=i; }
if (pts[i].x<pmin.x) { pmin.x=pts[i].x; bidx[1]=i; }
if (pts[i].y>pmax.y) { pmax.y=pts[i].y; bidx[2]=i; }
if (pts[i].y<pmin.y) { pmin.y=pts[i].y; bidx[3]=i; }
if (pts[i].z>pmax.z) { pmax.z=pts[i].z; bidx[4]=i; }
if (pts[i].z<pmin.z) { pmin.z=pts[i].z; bidx[5]=i; }
}
e = max(max(pmax.x-pmin.x,pmax.y-pmin.y),pmax.z-pmin.z)*0.01f;
// select 4 unique points from the 6 found above
for(k=0;k<2;k++) {
for(i=0;i<3;i++) for(j=i+1;j<4;j++) if (bidx[i]==bidx[j]) {
ti=bidx[4+k]; bidx[4+k]=bidx[j]; bidx[j]=ti;
goto nextk;
} break;
nextk:;
}
if (k==2) { // if 4 unique points cannot be found, select 4 arbitrary points
bidx[0]=0; bidx[1]=npts/3; bidx[2]=npts*2/3; bidx[3]=npts-1;
}
vectorf cp1 = pts[bidx[1]]-pts[bidx[0]] ^ pts[bidx[2]]-pts[bidx[0]];
if (sqr(cp1*(pts[bidx[3]]-pts[bidx[0]])) < cube(e)) { // coplanar points, find another 4th poind
for(i=0,maxdist=0; i<npts; i++) {
dist = fabs_tpl((pts[i]-pts[bidx[0]])*cp1);
if (dist > maxdist) {
maxdist=dist; bidx[3]=i;
}
}
}
// build a double linked list from all points
for(i=0;i<npts;i++) {
ptlist[i].prev = ptlist+i-1;
ptlist[i].next = ptlist+i+1;
}
ptlist[0].prev = ptlist+npts-1;
ptlist[npts-1].next = ptlist;
// remove selected points from the list
for(i=0;i<4;i++) delete_item_from_list(ptlist+bidx[i]);
// assign 3 points to each of 4 initial triangles
for(i=0;i<4;i++) {
for(j=k=0; j<4; j++)
if (j!=i) trbuf[i].idx[k++]=bidx[j]; // skip i.th point in i.th triangle
trbuf[i].n = pts[trbuf[i].idx[1]]-pts[trbuf[i].idx[0]] ^ pts[trbuf[i].idx[2]]-pts[trbuf[i].idx[0]];
trbuf[i].d = trbuf[i].n*pts[trbuf[i].idx[0]];
if (pts[bidx[i]]*trbuf[i].n > trbuf[i].d) { // flip the orientation so that ccw normal points outwards
ti=trbuf[i].idx[0]; trbuf[i].idx[0]=trbuf[i].idx[2]; trbuf[i].idx[2]=ti;
trbuf[i].n = -trbuf[i].n; trbuf[i].d = -trbuf[i].d;
}
trbuf[i].ptassoc = 0;
trbuf[i].deleted = 0;
add_item_to_list(trstart, trbuf+i);
}
// fill buddy links for each triangle
for(i=0;i<4;i++) for(j=0;j<4;j++) if (j!=i) for(k=0;k<3;k++) for(ti=0;ti<3;ti++)
if (trbuf[i].idx[k]==trbuf[j].idx[ti] && trbuf[i].idx[k==2?0:k+1]==trbuf[j].idx[ti==0?2:ti-1]) {
trbuf[i].buddy[k] = trbuf+j; break;
}
trend = trstart+4;
for(i=0;i<4;i++) if (trbuf[i].n.len2()<1E-6f) {
#ifdef _DEBUG
//OutputDebugString("WARNING: convex hull not computed because of degenerate initial triangles\n");
#endif
n=0; goto endqhull; // some degenerate case, don't party with it
}
// associate points with one of the initial triangles
for(i=0;i<npts;i++) if (ptlist[i].next) break;
associate_ptlist_with_trilist(ptlist+i, trstart, ptlist,pts, e);
#define DELETE_TRI(ptri) { \
merge_lists(ptdeleted, (ptri)->ptassoc); \
if ((ptri)==trstart) trstart=(ptri)->next; \
if ((ptri)==trnext) trnext=(ptri)->next; \
delete_item_from_list(ptri); (ptri)->deleted=1; \
}
// main loop
iter=0;maxiter=npts*npts*2;
tr=trstart; do {
trnext = tr->next;
pt=tr->ptassoc; if (pt) {
// find the fartherst of the associated with the triangle points
maxdist=-1E10; do {
if ((dist = pts[(int)(pt-ptlist)]*tr->n) > maxdist)
{ maxdist = dist; ptmax = pt; }
pt = pt->next;
} while (pt!=tr->ptassoc);
ptdeleted = 0;
if (tr->ptassoc==ptmax) tr->ptassoc=ptmax->next;
delete_item_from_list(ptmax);
if (tr->ptassoc==ptmax) tr->ptassoc=0;
// find the triangle that the point can see "most confidently"
tr=trstart; trlast=tr->prev; ti=ptmax-ptlist; maxdist=-1E10;
do {
trnext = tr->next;
if (pts[ti]*tr->n-tr->d > maxdist) {
maxdist = pts[ti]*tr->n-tr->d;
trbest = tr;
}
if (tr==trlast) break;
tr = trnext;
} while (true);
// "flood fill" triangles that the point can see around that one
DELETE_TRI(trbest)
tr = trbest->next=trbest->prev = trbest;
do {
if (!tr->buddy[0]->deleted && pts[ti]*tr->buddy[0]->n > tr->buddy[0]->d) {
DELETE_TRI(tr->buddy[0])
add_item_to_list(tr, tr->buddy[0]);
}
if (!tr->buddy[1]->deleted && pts[ti]*tr->buddy[1]->n > tr->buddy[1]->d) {
DELETE_TRI(tr->buddy[1])
add_item_to_list(tr, tr->buddy[1]);
}
if (!tr->buddy[2]->deleted && pts[ti]*tr->buddy[2]->n > tr->buddy[2]->d) {
DELETE_TRI(tr->buddy[2])
add_item_to_list(tr, tr->buddy[2]);
}
tr = tr->next;
} while(tr!=trbest);
/*// delete triangles that the point can see
tr=trstart; trlast=tr->prev; ti=ptmax-ptlist;
do {
trnext = tr->next;
if (pts[ti]*tr->n > tr->d)
DELETE_TRI(tr)
if (tr==trlast) break;
tr = trnext;
} while (true);*/
// delete near-visible triangles around deleted area edges to preserve hole convexity
// do as many iterations as needed
do {
tr=trstart; trlast=tr->prev; next_iter=0;
do {
trnext = tr->next;
if (pts[ti]*tr->n>tr->d-e*0.5f) {
delbuds = tr->buddy[0]->deleted+tr->buddy[1]->deleted+tr->buddy[2]->deleted;
if (delbuds >= 2) { // delete triangles that have 2+ buddies deleted
if (tr==trlast) trlast=tr->next;
DELETE_TRI(tr); next_iter=1;
} else if (delbuds==1) { // follow triangle fan around both shared edge ends
int bi,bi0,bi1,nfantris,fandir;
qhtritem *fantris[64],*tr1;
for(bi0=0; bi0<3 && !tr->buddy[bi0]->deleted; bi0++); // bi0 - deleted buddy index
for(fandir=-1; fandir<=1; fandir+=2) { // follow fans in 2 possible directions
tr1=tr; bi1=bi0; nfantris=0;
do {
bi=bi1+fandir; if (bi>2) bi-=3; if (bi<0) bi+=3;
for(bi1=0; bi1<3 && tr1->buddy[bi]->buddy[bi1]!=tr1; bi1++);
fantris[nfantris++] = tr1; // store this triangle in a temporary fan list
tr1=tr1->buddy[bi]; bi=bi1; // go to the next fan triangle
if (pts[ti]*tr1->n <= tr1->d-e) break; // discard this fan
if (tr1->deleted) {
if (tr1!=tr->buddy[bi0]) {
// delete fan only if it ended on _another_ deleted triangle
for(--nfantris;nfantris>=0;nfantris--) {
if (fantris[nfantris]==trlast) trlast=fantris[nfantris]->next;
DELETE_TRI(fantris[nfantris])
}
next_iter=1;
} break; // fan end
}
} while(true);
}
}
}
if (tr==trlast) break;
tr = trnext;
} while (tr);
} while (next_iter && trstart);
if (!trstart || trstart->deleted) {
#ifdef _DEBUG
//OutputDebugString("WARNING: convex hull not computed because all triangles were deleted (too thing or too small objects)\n");
#endif
n=0; goto endqhull;
}
// find triangles that shared an edge with deleted triangles
trnew=0; tr=trstart; do {
for(i=0;i<3;i++) if (tr->buddy[i]->deleted) {
// create a new triangle
if (trend>=trdata+trdatasz) {
qhtritem* trdata_new = new qhtritem[trdatasz+=256];
memcpy(trdata_new, trdata, (trend-trdata)*sizeof(qhtritem));
intptr_t diff = (intptr_t)trdata_new-(intptr_t)trdata;
for(n=0;n<trdatasz-256;n++)
relocate_tritem(trdata_new+n,diff);
relocate_ptritem(trend,diff); relocate_ptritem(trstart,diff);
relocate_ptritem(trnext,diff);relocate_ptritem(tr,diff);
relocate_ptritem(trbest,diff);relocate_ptritem(trnew,diff);
if (trdata!=trbuf) delete trdata;
trdata = trdata_new;
}
trend->idx[0] = ptmax-ptlist;
trend->idx[1] = tr->idx[i==2 ? 0:i+1];
trend->idx[2] = tr->idx[i];
trend->ptassoc = 0; trend->deleted = 0;
trend->n = pts[trend->idx[1]]-pts[trend->idx[0]] ^ pts[trend->idx[2]]-pts[trend->idx[0]];
trend->d = pts[trend->idx[0]]*trend->n;
trend->buddy[1] = tr; tr->buddy[i] = trend;
trend->buddy[0]=trend->buddy[2]=0;
add_item_to_list(trnew, trend++);
}
tr=tr->next;
} while (tr!=trstart);
// sort pointers to the new triangles by their 2nd vertex index
n=trend-trnew; if (tmparr_sz<n) {
if (tmparr_idx!=tmparr_idx_buf) delete tmparr_idx;
if (tmparr_ptr!=tmparr_ptr_buf) delete tmparr_ptr;
tmparr_idx = new int[n];
tmparr_ptr = new(qhtritem*[n]);
}
for(tr=trnew,i=0;tr<trend;tr++,i++) { tmparr_idx[i]=tr->idx[2]; tmparr_ptr[i]=tr; }
qsort(tmparr_idx,(void**)tmparr_ptr, 0,trend-trnew-1);
// find 0th buddy for each new triangle (i.e. the triangle, which has its idx[2]==tr->idx[1]
for(tr=trnew;tr<trend;tr++) {
i = bin_search(tmparr_idx,n, tr->idx[1]);
tr->buddy[0] = tmparr_ptr[i];
tmparr_ptr[i]->buddy[2] = tr;
}
for(tr=trnew;tr<trend;tr++)
if (!tr->buddy[0] || !tr->buddy[2]) {
#ifdef _DEBUG
//DEBUG_BREAK;
//OutputDebugString("WARNING: failed to compute convex hull due to geometric error\n");
#endif
goto endqh;
}
// assign all points from the deleted triangles to the new triangles
associate_ptlist_with_trilist(ptdeleted,trnew, ptlist,pts, e);
// add new triangles to the list
merge_lists(trnext, trnew);
} else if (trnext==trstart)
break; // all triangles in queue have no associated vertices
tr = trnext;
} while (++iter<maxiter);
#ifdef _DEBUG
//if (iter>=maxiter)
//OutputDebugString("WARNING: failed to compute convex hull during iterations limit\n");
#endif
endqh:
// build the final triangle list
for(tr=trstart,n=1; tr->next!=trstart; tr=tr->next,n++);
pTris = new index_t[n*3];
i=0; tr=trstart; do {
pTris[i]=tr->idx[0]; pTris[i+1]=tr->idx[1]; pTris[i+2]=tr->idx[2];
tr = tr->next; i+=3;
} while(tr!=trstart);
endqhull:
if (ptlist!=ptbuf) delete[] ptlist;
if (tmparr_idx!=tmparr_idx_buf) delete[] tmparr_idx;
if (tmparr_ptr!=tmparr_ptr_buf) delete[] tmparr_ptr;
if (trdata!=trbuf) delete[] trdata;
return n;
}
///////////////////////////// Qhull 2d ///////////////////////////////
inline void delete_item(ptitem2d *pitem, ptitem2d *&pref) {
pitem->next->prev = pitem->prev;
pitem->prev->next = pitem->next;
if (pref==pitem)
pref = pitem->next!=pitem ? pitem->next : 0;
}
inline void add_item(ptitem2d *pitem, ptitem2d *&pref) {
if (pref) {
pref->next->prev = pitem; pitem->next = pref->next;
pref->next = pitem; pitem->prev = pref;
} else {
pitem->next=pitem->prev = pitem;
pref = pitem;
}
}
int qhull2d(ptitem2d *pts,int nVtx, edgeitem *edges)
{
intptr_t imask;
int i,i0,i1,nEdges;
vector2df edge;
ptitem2d *ppt,*ppt_best,*ppt_next,*plist;
edgeitem *pedge,*pstart,*pend;
for(i=i0=0;i<nVtx;i++) { // find the 1st point - the one w/ max y
imask = -isneg(pts[i0].pt.y-pts[i].pt.y);
i0 = i&imask | i0&~imask;
}
// find the 2nd point - the one farthest from the 1st one
for(i1=0,i=1; i<nVtx; i++) {
imask = -isneg((pts[i1].pt-pts[i0].pt).len2()-(pts[i].pt-pts[i0].pt).len2());
i1 = i&imask | i1&~imask;
}
// form the 1st two edges
edges[0].prev=edges[0].next=edges+1; edges[0].pvtx=pts+i0; edges[0].plist=0;
edges[1].prev=edges[1].next=edges+0; edges[1].pvtx=pts+i1; edges[1].plist=0;
edge = pts[i1].pt-pts[i0].pt;
for(i=0; i<nVtx; i++) if ((i-i0)*(i-i1))
add_item(pts+i,edges[isneg(pts[i].pt-pts[i0].pt ^ edge)].plist);
nEdges = 2;
do {
for(i=0;i<nEdges && !edges[i].plist;i++);
if (i==nEdges)
break;
// find up the farthest point associated with the edge
edge = edges[i].next->pvtx->pt-edges[i].pvtx->pt; ppt=ppt_best = edges[i].plist;
do {
imask = -(intptr_t)isneg((ppt_best->pt-edges[i].pvtx->pt^edge) - (ppt->pt-edges[i].pvtx->pt^edge));
ppt_best = (ptitem2d*)((intptr_t)ppt&imask | (intptr_t)ppt_best&~imask);
} while((ppt=ppt->next)!=edges[i].plist);
// trace contour from i cw while edges are facing the point ppt_best (pstart - 1st edge to be deleted)
for(pstart=edges+i; pstart->prev!=edges+i &&
(ppt_best->pt-pstart->prev->pvtx->pt ^ pstart->pvtx->pt-pstart->prev->pvtx->pt)>0; pstart=pstart->prev);
// trace contour from i ccw while edges are facing the point ppt_best (pend - edge after the last edge to be deleted)
for(pend=edges[i].next; pend!=edges+i &&
(ppt_best->pt-pend->pvtx->pt ^ pend->next->pvtx->pt-pend->pvtx->pt)>0; pend=pend->next);
// delete point ppt_best from the ith edge associated list
delete_item(ppt_best,edges[i].plist);
// merge point lists for edges pstart-pend
for(pedge=pstart,plist=0; pedge!=pend && !pedge->plist; pedge=pedge->next);
if (pedge!=pend) for(plist=pedge->plist,pedge->plist=0,pedge=pedge->next; pedge!=pend; pedge=pedge->next) if (pedge->plist) {
plist->next->prev = pedge->plist->prev; pedge->plist->prev->next = plist->next;
plist->next = pedge->plist; pedge->plist->prev = plist;
pedge->plist = 0;
}
// create a new edge between pstart and pend (first one will override pstart)
pstart->next=edges+nEdges; edges[nEdges].prev=pstart;
pend->prev = edges+nEdges; edges[nEdges].next=pend;
edges[nEdges].pvtx = ppt_best;
pstart->plist = edges[nEdges].plist = 0;
// associate some points from that list with one of the 2 new edges
if (plist) {
edgeitem *pedge[2]; vector2df edge[2]; float dist[2];
ppt = plist; pedge[0] = pstart; pedge[1] = edges+nEdges;
edge[0] = pedge[0]->next->pvtx->pt-pedge[0]->pvtx->pt;
edge[1] = pedge[1]->next->pvtx->pt-pedge[1]->pvtx->pt;
do {
ppt_next = ppt->next;
dist[0] = (ppt->pt-pedge[0]->pvtx->pt ^ edge[0])*edge[1].len2();
dist[1] = (ppt->pt-pedge[1]->pvtx->pt ^ edge[1])*edge[0].len2();
i = isneg(dist[0]-dist[1]);
if (dist[i]>0)
add_item(ppt,pedge[i]->plist);
} while((ppt=ppt_next)!=plist);
}
nEdges++;
} while(true);
return nEdges;
}

145
CryPhysics/quotient.h Normal file
View File

@@ -0,0 +1,145 @@
//////////////////////////////////////////////////////////////////////
//
// Quotient header
//
// File: quotient.h
// Description : quotient template class declaration and inlined implementation
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#ifndef quotient_h
#define quotient_h
#pragma once
// warning: all comparisons assume quotent's y>=0, use fixsign() to ensure this is the case
template<class ftype> class quotient_tpl {
public:
quotient_tpl() {}
quotient_tpl(type_min) { x=-1;y=0; }
quotient_tpl(type_max) { x=1;y=0; }
explicit quotient_tpl(ftype _x,ftype _y=1) { x=_x;y=_y; }
quotient_tpl(const quotient_tpl<ftype>& src) { x=src.x;y=src.y; }
template<class ftype1> quotient_tpl(const quotient_tpl<ftype1>& src) { x=src.x;y=src.y; }
template<class ftype1,class ftype2> quotient_tpl& set(ftype1 nx,ftype2 ny) { (*this=nx)/=ny; return *this; }
quotient_tpl& operator=(const quotient_tpl<ftype>& src) { x=src.x;y=src.y; return *this; }
template<class ftype1> quotient_tpl& operator=(const quotient_tpl<ftype1>& src) { x=src.x;y=src.y; return *this; }
quotient_tpl& operator=(ftype src) { x=src;y=1; return *this; }
quotient_tpl& fixsign() { int sgny=::sgnnz(y); x*=sgny; y*=sgny; return *this; }
ftype val() { return y!=0 ? x/y : 0; }
quotient_tpl operator-() const { return quotient_tpl(-x,y); }
quotient_tpl operator*(ftype op) const { return quotient_tpl(x*op,y); }
quotient_tpl operator/(ftype op) const { return quotient_tpl(x,y*op); }
quotient_tpl operator+(ftype op) const { return quotient_tpl(x+y*op,y); }
quotient_tpl operator-(ftype op) const { return quotient_tpl(x-y*op,y); }
quotient_tpl& operator*=(ftype op) { x*=op; return *this; }
quotient_tpl& operator/=(ftype op) { y*=op; return *this; }
quotient_tpl& operator+=(ftype op) { x+=op*y; return *this; }
quotient_tpl& operator-=(ftype op) { x-=op*y; return *this; }
bool operator==(ftype op) const { return x==op*y; }
bool operator!=(ftype op) const { return x!=op*y; }
bool operator<(ftype op) const { return x-op*y<0; }
bool operator>(ftype op) const { return x-op*y>0; }
bool operator<=(ftype op) const { return x-op*y<=0; }
bool operator>=(ftype op) const { return x-op*y>=0; }
int sgn() { return ::sgn(x); }
int sgnnz() { return ::sgnnz(x); }
int isneg() { return ::isneg(x); }
int isnonneg() { return ::isnonneg(x); }
int isin01() { return ::isneg(fabs_tpl(x*2-y)-fabs_tpl(y)); }
ftype x,y;
};
template<> inline quotient_tpl<float>::quotient_tpl(type_min) { x=-1;y=1E-15f; }
template<> inline quotient_tpl<float>::quotient_tpl(type_max) { x=1;y=1E-15f; }
template<> inline quotient_tpl<double>::quotient_tpl(type_min) { x=-1;y=1E-50f; }
template<> inline quotient_tpl<double>::quotient_tpl(type_max) { x=1;y=1E-50f; }
template<class ftype1,class ftype2>
quotient_tpl<ftype1> operator*(const quotient_tpl<ftype1> &op1,const quotient_tpl<ftype2> &op2) { return quotient_tpl<ftype1>(op1.x*op2.x,op1.y*op2.y); }
template<class ftype1,class ftype2>
quotient_tpl<ftype1> operator/(const quotient_tpl<ftype1> &op1,const quotient_tpl<ftype2> &op2) { return quotient_tpl<ftype1>(op1.x*op2.y,op1.y*op2.x); }
template<class ftype1,class ftype2>
quotient_tpl<ftype1> operator+(const quotient_tpl<ftype1> &op1,const quotient_tpl<ftype2> &op2)
{ return /*op1.y==op2.y ? quotient_tpl<ftype1>(op1.x+op2.x,op1.y) :*/ quotient_tpl<ftype1>(op1.x*op2.y+op2.x*op1.y, op1.y*op2.y); }
template<class ftype1,class ftype2>
quotient_tpl<ftype1> operator-(const quotient_tpl<ftype1> &op1,const quotient_tpl<ftype2> &op2)
{ return /*op1.y==op2.y ? quotient_tpl<ftype1>(op1.x-op2.x,op1.y) :*/ quotient_tpl<ftype1>(op1.x*op2.y-op2.x*op1.y, op1.y*op2.y); }
template<class ftype1,class ftype2>
quotient_tpl<ftype1>& operator*=(quotient_tpl<ftype1> &op1,const quotient_tpl<ftype2> &op2) { op1.x*=op2.x; op1.y*=op2.y; return op1; }
template<class ftype1,class ftype2>
quotient_tpl<ftype1>& operator/=(quotient_tpl<ftype1> &op1,const quotient_tpl<ftype2> &op2) { op1.x*=op2.y; op1.y*=op2.x; return op1; }
template<class ftype1,class ftype2> quotient_tpl<ftype1>& operator+=(quotient_tpl<ftype1> &op1,const quotient_tpl<ftype2> &op2)
{ /*if (op1.y==op2.y) op1.x+=op2.x; else*/ { op1.x=op1.x*op2.y+op2.x*op1.y; op1.y*=op2.y; } return op1; }
template<class ftype1,class ftype2> quotient_tpl<ftype1>& operator-=(quotient_tpl<ftype1> &op1,const quotient_tpl<ftype2> &op2)
{ /*if (op1.y==op2.y) op1.x-=op2.x; else*/ { op1.x=op1.x*op2.y-op2.x*op1.y; op1.y*=op2.y; } return op1; }
template<class ftype> quotient_tpl<ftype> operator*(ftype op, const quotient_tpl<ftype> &q) { return quotient_tpl<ftype>(q.x*op,q.y); }
template<class ftype> quotient_tpl<ftype> operator/(ftype op, const quotient_tpl<ftype> &q) { return quotient_tpl<ftype>(q.x,q.y*op); }
template<class ftype> quotient_tpl<ftype> operator+(ftype op, const quotient_tpl<ftype> &q) { return quotient_tpl<ftype>(op*q.y+q.x,q.y); }
template<class ftype> quotient_tpl<ftype> operator-(ftype op, const quotient_tpl<ftype> &q) { return quotient_tpl<ftype>(op*q.y-q.x,q.y); }
template<class ftype> bool operator==(ftype op1, const quotient_tpl<ftype> &op2) { return op1*op2.y==op2.x; }
template<class ftype> bool operator!=(ftype op1, const quotient_tpl<ftype> &op2) { return op1*op2.y!=op2.x; }
template<class ftype> bool operator<(ftype op1, const quotient_tpl<ftype> &op2) { return op1*op2.y-op2.x<0; }
template<class ftype> bool operator>(ftype op1, const quotient_tpl<ftype> &op2) { return op1*op2.y-op2.x>0; }
template<class ftype> bool operator<=(ftype op1, const quotient_tpl<ftype> &op2) { return op1*op2.y-op2.x<=0; }
template<class ftype> bool operator>=(ftype op1, const quotient_tpl<ftype> &op2) { return op1*op2.y-op2.x>=0; }
template<class ftype1,class ftype2> bool operator==(const quotient_tpl<ftype1> &op1, const quotient_tpl<ftype2> &op2)
{ return op1.x*op2.y==op2.x*op1.y; }
template<class ftype1,class ftype2> bool operator!=(const quotient_tpl<ftype1> &op1, const quotient_tpl<ftype2> &op2)
{ return op1.x*op2.y!=op2.x*op1.y; }
template<class ftype1,class ftype2> bool operator<(const quotient_tpl<ftype1> &op1, const quotient_tpl<ftype2> &op2)
{ return op1.x*op2.y-op2.x*op1.y < 0; }
template<class ftype1,class ftype2> bool operator>(const quotient_tpl<ftype1> &op1, const quotient_tpl<ftype2> &op2)
{ return op1.x*op2.y-op2.x*op1.y > 0; }
template<class ftype1,class ftype2> bool operator<=(const quotient_tpl<ftype1> &op1, const quotient_tpl<ftype2> &op2)
{ return op1.x*op2.y-op2.x*op1.y <= 0; }
template<class ftype1,class ftype2> bool operator>=(const quotient_tpl<ftype1> &op1, const quotient_tpl<ftype2> &op2)
{ return op1.x*op2.y-op2.x*op1.y >= 0; }
template<class ftype> int sgn(const quotient_tpl<ftype> &op) { return sgn(op.x); }
template<class ftype> int sgnnz(const quotient_tpl<ftype> &op) { return sgnnz(op.x); }
template<class ftype> int isneg(const quotient_tpl<ftype> &op) { return isneg(op.x); }
template<class ftype> int isnonneg(const quotient_tpl<ftype> &op) { return isnonneg(op.x); }
template<class ftype> int sgn_safe(const quotient_tpl<ftype> &op) { return sgn(op.x)*sgnnz(op.y); }
template<class ftype> int sgnnz_safe(const quotient_tpl<ftype> &op) { return sgnnz(op.x)*sgnnz(op.y); }
template<class ftype> int isneg_safe(const quotient_tpl<ftype> &op) { return isneg(op.x)^isneg(op.y); }
template<class ftype> int isnonneg_safe(const quotient_tpl<ftype> &op) { return isnonneg(op.x)*isnonneg(op.y); }
template<class ftype> quotient_tpl<ftype> fabs_tpl(const quotient_tpl<ftype> op) { return quotient_tpl<ftype>(fabs_tpl(op.x),fabs_tpl(op.y)); }
template<class ftype> quotient_tpl<ftype> max(const quotient_tpl<ftype> &op1,const quotient_tpl<ftype> &op2) {
int mask1=isneg(op2.x*op1.y-op1.x*op2.y), mask2=mask1^1;
return quotient_tpl<ftype>(op1.x*mask1+op2.x*mask2, op1.y*mask1+op2.y*mask2);
}
template<class ftype> quotient_tpl<ftype> min(const quotient_tpl<ftype> &op1,const quotient_tpl<ftype> &op2) {
int mask1=isneg(op1.x*op2.y-op2.x*op1.y), mask2=mask1^1;
return quotient_tpl<ftype>(op1.x*mask1+op2.x*mask2, op1.y*mask1+op2.y*mask2);
}
template<class ftype> quotient_tpl<ftype> fake_atan2(ftype y,ftype x) {
quotient_tpl<ftype> res;
ftype src[2] = { x,y };
int ix=isneg(x),iy=isneg(y),iflip=isneg(fabs_tpl(x)-fabs_tpl(y));
res.x = src[iflip^1]*(1-iflip*2)*sgnnz(src[iflip]); res.y = fabs_tpl(src[iflip]);
res += (iy*2+(ix^iy)+(iflip^ix^iy))*2;
return res;
}
typedef quotient_tpl<float> quotientf;
typedef quotient_tpl<real> quotient;
typedef quotient_tpl<int> quotienti;
#endif

33
CryPhysics/raybv.cpp Normal file
View File

@@ -0,0 +1,33 @@
#include "stdafx.h"
#include "utils.h"
#include "primitives.h"
#include "bvtree.h"
#include "geometry.h"
#include "raybv.h"
BVray CRayBV::g_BVray;
int CRayBV::GetNodeContents(int iNode, BV *pBVCollider,int bColliderUsed,int bColliderLocal,
geometry_under_test *pGTest,geometry_under_test *pGTestOp)
{
return 1; // ray should already be in the buffer
}
void CRayBV::GetNodeBV(BV *&pBV, int iNode)
{
pBV = &g_BVray;
g_BVray.iNode = 0;
g_BVray.type = ray::type;
g_BVray.aray.origin = m_pray->origin;
g_BVray.aray.dir = m_pray->dir;
}
void CRayBV::GetNodeBV(const matrix3x3f &Rw,const vectorf &offsw,float scalew, BV *&pBV, int iNode)
{
pBV = &g_BVray;
g_BVray.iNode = 0;
g_BVray.type = ray::type;
g_BVray.aray.origin = Rw*m_pray->origin*scalew + offsw;
g_BVray.aray.dir = Rw*m_pray->dir*scalew;
}

24
CryPhysics/raybv.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef raybv_h
#define raybv_h
#pragma once
class CRayBV : public CBVTree {
public:
CRayBV() {}
virtual int GetType() { return BVT_RAY; }
virtual float Build(CGeometry *pGeom) { m_pGeom=pGeom; return 0.0f; }
void SetRay(ray *pray) { m_pray = pray; }
virtual void GetNodeBV(BV *&pBV, int iNode=0);
virtual void GetNodeBV(BV *&pBV, const vectorf &sweepdir,float sweepstep, int iNode=0) {}
virtual void GetNodeBV(const matrix3x3f &Rw,const vectorf &offsw,float scalew, BV *&pBV, int iNode=0);
virtual void GetNodeBV(const matrix3x3f &Rw,const vectorf &offsw,float scalew, BV *&pBV, const vectorf &sweepdir,float sweepstep, int iNode=0) {}
virtual int GetNodeContents(int iNode, BV *pBVCollider,int bColliderUsed,int bColliderLocal,
geometry_under_test *pGTest,geometry_under_test *pGTestOp);
CGeometry *m_pGeom;
ray *m_pray;
static BVray g_BVray;
};
#endif

70
CryPhysics/raygeom.cpp Normal file
View File

@@ -0,0 +1,70 @@
#include "stdafx.h"
#include "utils.h"
#include "primitives.h"
#include "bvtree.h"
#include "geometry.h"
#include "raybv.h"
#include "raygeom.h"
void CRayGeom::GetBBox(box *pbox)
{
pbox->Basis.SetRow(2,m_dirn);
//pbox->Basis.SetRow(1,m_dirn.orthogonal().normalized());
pbox->Basis.SetRow(1,GetOrthogonal(m_dirn).normalized());
pbox->Basis.SetRow(0,pbox->Basis.GetRow(1)^m_dirn);
}
int CRayGeom::PrepareForIntersectionTest(geometry_under_test *pGTest, CGeometry *pCollider,geometry_under_test *pGTestColl, bool bKeepPrevContacts)
{
static short g_id = -1;
m_Tree.PrepareForIntersectionTest(pGTest);
pGTest->pGeometry = this;
pGTest->pBVtree = &m_Tree;
pGTest->primbuf = pGTest->primbuf1 = &m_ray;
pGTest->typeprim = ray::type;
pGTest->szprim = sizeof(ray);
pGTest->idbuf = &g_id;
pGTest->surfaces = 0;
pGTest->edges = 0;
pGTest->minAreaEdge = 0;
return 1;
}
int CRayGeom::PreparePrimitive(geom_world_data *pgwd, primitive *&pprim)
{
pprim = &m_ray;
return ray::type;
}
int CRayGeom::GetPrimitiveList(int iStart,int nPrims, int typeCollider,primitive *pCollider,int bColliderLocal,
geometry_under_test *pGTest,geometry_under_test *pGTestOp, primitive *pRes,short *pResId)
{
return 1;
}
int CRayGeom::RegisterIntersection(primitive *pprim1,primitive *pprim2, geometry_under_test *pGTest1,geometry_under_test *pGTest2, prim_inters *pinters)
{
geom_contact *pres = pGTest1->contacts + *pGTest1->pnContacts;
(*pGTest1->pnContacts)++;
pres->ptborder = &pres->pt;
pres->nborderpt = 1;
pres->parea = 0;
pres->t = (pinters->pt[0]-m_ray.origin)*m_dirn;
pres->pt = pinters->pt[0];
pres->n = -pinters->n;
pres->dir.zero();
pres->vel = 0;
pres->iUnprojMode = 0;
pres->id[0] = -1;
pres->id[1] = pinters->id[1];
pres->iPrim[0] = 0; pres->iFeature[0] = 0x20;
pres->iPrim[1] = pGTest2 && pGTest2->typeprim==indexed_triangle::type ? ((indexed_triangle*)pprim2)->idx : 0;
pres->iFeature[1] = pinters->iFeature[0][1];
pres->iNode[0] = pinters->iNode[0];
pres->iNode[1] = pinters->iNode[1];
if (*pGTest1->pnContacts>=pGTest1->nMaxContacts || pGTest1->pParams->bStopAtFirstTri)
pGTest1->bStopIntersection = 1;
return 1;
}

37
CryPhysics/raygeom.h Normal file
View File

@@ -0,0 +1,37 @@
#ifndef raygeom_h
#define raygeom_h
#pragma once
class CRayGeom : public CGeometry {
public:
CRayGeom() { m_iCollPriority=0; m_Tree.Build(this); m_Tree.SetRay(&m_ray); m_minVtxDist=1.0f; }
CRayGeom(const ray *pray) {
m_iCollPriority=0; m_ray.origin = pray->origin; m_ray.dir = pray->dir; m_dirn = pray->dir.normalized();
m_Tree.Build(this); m_Tree.SetRay(&m_ray); m_minVtxDist=1.0f;
}
CRayGeom(const vectorf &origin, const vectorf &dir) {
m_iCollPriority=0; m_ray.origin = origin; m_ray.dir = dir; m_dirn = dir.normalized();
m_Tree.Build(this); m_Tree.SetRay(&m_ray); m_minVtxDist=1.0f;
}
CRayGeom *CreateRay(const vectorf &origin, const vectorf &dir, const vectorf *pdirn=0) {
m_ray.origin = origin; m_ray.dir = dir; m_dirn = pdirn ? *pdirn : dir.normalized(); return this;
}
virtual int GetType() { return GEOM_RAY; }
virtual int IsAPrimitive() { return 1; }
virtual void GetBBox(box *pbox);
virtual int PrepareForIntersectionTest(geometry_under_test *pGTest, CGeometry *pCollider,geometry_under_test *pGTestColl, bool bKeepPrevContacts);
virtual int RegisterIntersection(primitive *pprim1,primitive *pprim2, geometry_under_test *pGTest1,geometry_under_test *pGTest2,
prim_inters *pinters);
virtual int GetPrimitiveList(int iStart,int nPrims, int typeCollider,primitive *pCollider,int bColliderLocal,
geometry_under_test *pGTest,geometry_under_test *pGTestOp, primitive *pRes,short *pResId);
virtual int PreparePrimitive(geom_world_data *pgwd,primitive *&pprim);
virtual CBVTree *GetBVTree() { return &m_Tree; }
virtual int GetPrimitive(int iPrim, primitive *pprim) { *(ray*)pprim = m_ray; return sizeof(ray); }
ray m_ray;
vectorf m_dirn;
CRayBV m_Tree;
};
#endif

1237
CryPhysics/rigidbody.cpp Normal file

File diff suppressed because it is too large Load Diff

115
CryPhysics/rigidbody.h Normal file
View File

@@ -0,0 +1,115 @@
//////////////////////////////////////////////////////////////////////
//
// Rigid Body header
//
// File: rigidbody.cpp
// Description : RigidBody class declaration
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#ifndef rigidbody_h
#define rigidbody_h
#pragma once
struct entity_contact;
const int MAX_CONTACTS = 4096;
enum solver_events { solver_initialize, solver_end_iter, solver_end };
class IRigidBodyOwner {
public:
virtual void AddImpulseAtContact(entity_contact *pcontact, int iop, const vectorf &dP) = 0;
virtual vectorf GetVelocityAtContact(entity_contact *pcontact, int iop) = 0;
virtual int OnRegisterContact(entity_contact *pcontact, int iop) = 0;
virtual void OnSolverEvent(int iEvent) = 0;
};
class RigidBody : public IRigidBodyOwner {
public:
RigidBody();
void Create(const vectorf &center,const vectorf &Ibody0,const quaternionf &q0, float volume,float mass,
const quaternionf &qframe,const vectorf &posframe);
void Add(const vectorf &center,const vectorf Ibodyop,const quaternionf &qop, float volume,float mass);
void zero();
void Step(float dt);
void UpdateState();
void GetContactMatrix(const vectorf &r, matrix3x3f &K);
virtual void AddImpulseAtContact(entity_contact *pcontact, int iop, const vectorf &dP);
virtual vectorf GetVelocityAtContact(entity_contact *pcontact, int iop);
virtual int OnRegisterContact(entity_contact *pcontact, int iop) { return 1; }
virtual void OnSolverEvent(int iEvent) {}
vectorf pos;
quaternionf q;
vectorf P,L;
vectorf w,v;
float M,Minv; // mass, 1.0/mass (0 for static objects)
float V; // volume
matrix3x3diagf Ibody; // diagonalized inertia tensor (aligned with body's axes of inertia)
matrix3x3diagf Ibody_inv; // { 1/Ibody.ii }
quaternionf qfb; // frame->body rotation
vectorf offsfb; // frame->body offset
matrix3x3f Iinv; // I^-1(t)
vectorf Fcollision,Tcollision;
int bProcessed; // used internally
float Eunproj;
float softness[2];
IRigidBodyOwner *pOwner;
};
enum contactflags { contact_count_mask=0x3F, contact_new=0x40, contact_2b_verified=0x80, contact_2b_verified_log2=7,
contact_angular=0x100, contact_constraint_3dof=0x200, contact_constraint_2dof=0x400,
contact_constraint_1dof=0x800, contact_solve_for=0x1000,
contact_constraint=contact_constraint_3dof|contact_constraint_2dof|contact_constraint_1dof,
contact_angular_log2=8,contact_bidx=0x2000,contact_bidx_log2=13, contact_maintain_count=0x4000,
contact_wheel=0x8000, contact_use_C=0x10000, contact_inexact=0x20000 };
class CPhysicalEntity;
struct entity_contact {
vectorf pt[2];
vectorf n;
vectorf dir;
vectorf ptloc[2];
CPhysicalEntity *pent[2];
int ipart[2];
RigidBody *pbody[2];
vectorf nloc;
float friction;
int id[2];
int flags;
vectorf vrel;
vectorf vreq;
//float vsep;
float Pspare;
float penetration;
matrix3x3f K,Kinv;
matrix3x3f C;
int iNormal;
int iPrim[2];
int iFeature[2];
int bProcessed;
int iCount,*pBounceCount;
vectorf r0,r;
vectorf dP,P;
float dPn;
};
extern bool g_bUsePreCG;
extern int g_nContacts,g_nBodies;
void InitContactSolver(float time_interval);
void RegisterContact(entity_contact *pcontact);
void InvokeContactSolver(float time_interval, SolverSettings *pss);
char *AllocSolverTmpBuf(int size);
#endif

2797
CryPhysics/rigidentity.cpp Normal file

File diff suppressed because it is too large Load Diff

180
CryPhysics/rigidentity.h Normal file
View File

@@ -0,0 +1,180 @@
//////////////////////////////////////////////////////////////////////
//
// Rigid Entity header
//
// File: rigidentity.h
// Description : RigidEntity class declaration
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#ifndef rigidentity_h
#define rigidentity_h
#pragma once
typedef uint64 masktype;
#define getmask(i) ((uint64)1<<(i))
const int NMASKBITS = 64;
enum rentity_flags_int {
ref_contact_overflow = 0x4000000
};
//typedef unsigned int masktype;
//#define getmask(i) (1u<<(i))
//const int NMASKBITS = 32;
enum constr_info_flags { constraint_limited_1axis=1, constraint_limited_2axes=2, constraint_rope=4 };
struct constraint_info {
quaternionf qframe_rel[2];
float limits[2];
unsigned int flags;
CPhysicalEntity *pConstraintEnt;
int bActive;
};
struct checksum_item {
int iPhysTime;
unsigned int checksum;
};
const int NCHECKSUMS = 32;
class CRigidEntity : public CPhysicalEntity {
public:
CRigidEntity(CPhysicalWorld *pworld);
virtual ~CRigidEntity();
virtual pe_type GetType() { return PE_RIGID; }
virtual int AddGeometry(phys_geometry *pgeom, pe_geomparams* params,int id=-1);
virtual void RemoveGeometry(int id);
virtual int SetParams(pe_params *_params);
virtual int GetParams(pe_params *_params);
virtual int GetStatus(pe_status*);
virtual int Action(pe_action*);
virtual int AddCollider(CPhysicalEntity *pCollider);
virtual int RemoveCollider(CPhysicalEntity *pCollider, bool bRemoveAlways=true);
virtual int RemoveContactPoint(CPhysicalEntity *pCollider, const vectorf &pt, float mindist2);
virtual int HasContactsWith(CPhysicalEntity *pent);
virtual int HasCollisionContactsWith(CPhysicalEntity *pent);
virtual int Awake(int bAwake=1,int iSource=0);
virtual int IsAwake(int ipart=-1) { return m_bAwake; }
virtual void AlertNeighbourhoodND();
virtual RigidBody *GetRigidBody(int ipart=-1) { return &m_body; }
virtual void GetContactMatrix(const vectorf &pt, int ipart, matrix3x3f &K) { m_body.GetContactMatrix(pt-m_body.pos,K); }
virtual float GetMassInv() { return m_body.Minv; }
enum snapver { SNAPSHOT_VERSION = 9 };
virtual int GetSnapshotVersion() { return SNAPSHOT_VERSION; }
virtual int GetStateSnapshot(class CStream &stm, float time_back=0, int flags=0);
virtual int SetStateFromSnapshot(class CStream &stm, int flags=0);
virtual int PostSetStateFromSnapshot();
virtual unsigned int GetStateChecksum();
int WriteContacts(CStream &stm,int flags);
int ReadContacts(CStream &stm,int flags);
virtual void StartStep(float time_interval);
virtual float GetMaxTimeStep(float time_interval);
virtual float GetLastTimeStep(float time_interval) { return m_lastTimeStep; }
virtual int Step(float time_interval);
virtual void StepBack(float time_interval);
virtual int GetContactCount(int nMaxPlaneContacts);
virtual int RegisterContacts(float time_interval,int nMaxPlaneContacts);
virtual int Update(float time_interval, float damping);
virtual float CalcEnergy(float time_interval);
virtual float GetDamping(float time_interval);
virtual void CheckAdditionalGeometry(float time_interval, masktype &contact_mask) {}
virtual void AddAdditionalImpulses(float time_interval) {}
virtual void RecomputeMassDistribution(int ipart=-1,int bMassChanged=1);
virtual void DrawHelperInformation(void (*DrawLineFunc)(float*,float*), int flags);
virtual void GetMemoryStatistics(ICrySizer *pSizer);
int RegisterConstraint(const vectorf &pt0,const vectorf &pt1, int ipart0, CPhysicalEntity *pBuddy,int ipart1, int flags);
int RemoveConstraint(int iConstraint);
int RegisterContactPoint(masktype &contact_mask, int idx, const vectorf &pt, const geom_contact *pcontacts, int iPrim0,int iFeature0,
int iPrim1,int iFeature1, int flags=contact_new, float penetration=0);
int CheckForNewContacts(geom_world_data *pgwd0,intersection_params *pip, int &itmax, int iStartPart=0,int nParts=-1);
virtual int GetPotentialColliders(CPhysicalEntity **&pentlist);
virtual int CheckSelfCollision(int ipart0,int ipart1) { return 0; }
void UpdatePenaltyContacts(float time_interval);
int UpdatePenaltyContact(int i, float time_interval);
int VerifyExistingContacts(float maxdist);
void UpdateConstraints();
void UpdateContactsAfterStepBack(float time_interval);
void ApplyBuoyancy(float time_interval,const vectorf &gravity);
void ArchiveContact(int idx);
int CompactContactBlock(masktype &contact_mask, float maxPlaneDist, int nMaxContacts,int &nContacts, vectorf &n, float &maxDist,
const vectorf& ptTest = vectorf(zero), const vectorf& dirTest = vectorf(zero));
int IsFast(float time_interval);
masktype *m_pColliderContacts,*m_pColliderConstraints;
entity_contact *m_pContacts,*m_pConstraints;
constraint_info *m_pConstraintInfos;
int m_nContactsAlloc,m_nConstraintsAlloc;
//int m_iStickyContacts[8],m_nStickyContacts;
//int m_iSlidingContacts[8],m_nSlidingContacts;
int m_bProhibitUnproj;
int m_bProhibitUnprojection,m_bEnforceContacts;
vectorf m_prevUnprojDir;
int m_bCollisionCulling;
int m_bJustLoaded;
int m_bStable;
int m_bHadSeverePenetration;
unsigned int m_nRestMask;
int m_nPrevColliders;
int m_bSteppedBack,m_nStepBackCount;
float m_velFastDir,m_sizeFastDir;
int m_bCanSweep;
float m_timeStepFull;
float m_timeStepPerformed;
float m_lastTimeStep;
float m_minAwakeTime;
vectorf m_gravity,m_gravityFreefall;
float m_Emin;
float m_maxAllowedStep;
vectorf m_vhist[4],m_whist[4],m_Lhist[4];
int m_iDynHist;
int m_bAwake;
int m_nSleepFrames;
float m_damping,m_dampingFreefall;
float m_dampingEx;
float m_maxw;
float m_softness[4];
RigidBody m_body;
vectorf m_Pext[2],m_Lext[2];
vectorf m_prevPos,m_prevv,m_prevw;
quaternionf m_prevq;
float m_E0,m_Estep;
float m_impulseTime;
float m_timeContactOverflow;
coll_history_item m_CollHistory[8];
int m_iCollHistory;
plane m_waterPlane;
float m_waterDensity;
float m_waterDamping;
float m_waterResistance;
vectorf m_waterFlow;
float m_EminWater;
int m_bFloating;
float m_submergedFraction;
float m_maxWaterResistance2;
checksum_item m_checksums[NCHECKSUMS];
int m_iLastChecksum;
};
extern CPhysicalEntity *g_CurColliders[128];
extern int g_CurCollParts[128][2];
#endif

801
CryPhysics/ropeentity.cpp Normal file
View File

@@ -0,0 +1,801 @@
//////////////////////////////////////////////////////////////////////
//
// Rope Entity
//
// File: ropeentity.cpp
// Description : CRopeEntity class implementation
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "bvtree.h"
#include "geometry.h"
#include "overlapchecks.h"
#include "raybv.h"
#include "raygeom.h"
#include "rigidbody.h"
#include "physicalplaceholder.h"
#include "physicalentity.h"
#include "geoman.h"
#include "physicalworld.h"
#include "ropeentity.h"
CRopeEntity::CRopeEntity(CPhysicalWorld *pWorld) : CPhysicalEntity(pWorld)
{
m_nSegs = -1;
m_segs = 0;
m_length = 0;
m_pTiedTo[0] = m_pTiedTo[1] = 0;
m_iTiedPart[0] = m_iTiedPart[1] = 0;
m_idConstraint = 0;
m_iConstraintClient = 0;
m_gravity = pWorld->m_vars.gravity;
m_bAwake = m_nSlowFrames = 0;
m_damping = 0.5f;
m_iSimClass = 4;
m_Emin = sqr(0.003f);
m_maxAllowedStep = 0.01f;
m_mass = 1.0f;
m_collDist = 0.01f;
m_flags = 0;
m_surface_idx = 0;
m_ig[0].x=m_ig[1].x=m_ig[0].y=m_ig[1].y = -3;
m_defpart.id = 0;
m_friction = 0.2f;
}
CRopeEntity::~CRopeEntity()
{
if (m_segs)
delete[] m_segs;
}
void CRopeEntity::AlertNeighbourhoodND()
{
pe_params_rope pr;
pr.pEntTiedTo[0] = pr.pEntTiedTo[1] = 0;
SetParams(&pr);
if (m_segs)
delete[] m_segs;
m_segs = 0; m_nSegs = 0;
}
int CRopeEntity::Awake(int bAwake,int iSource)
{
m_bAwake=bAwake; m_nSlowFrames=0;
int i;
if (m_nSegs>0) {
for(i=0;i<=m_nSegs;i++) if (m_segs[i].pContactEnt && m_segs[i].pContactEnt->m_iSimClass==7)
m_segs[i].pContactEnt = 0;
for(i=0;i<2;i++) if (m_pTiedTo[i] && m_pTiedTo[i]->m_iSimClass==7)
m_pTiedTo[i] = 0;
}
return 1;
}
int CRopeEntity::SetParams(pe_params *_params)
{
int res;
vectorf prevpos = m_pos;
if (res = CPhysicalEntity::SetParams(_params)) {
if (_params->type==pe_params_pos::type_id) {
//matrix3x3f R; m_qrot.getmatrix(R); //Q2M_IVO
matrix3x3f R = matrix3x3f(m_qrot);
for(int i=0;i<=m_nSegs;i++) {
m_segs[i].pt = R*(m_segs[i].pt-prevpos)+m_pos;
m_segs[i].vel = R*m_segs[i].vel;
m_segs[i].dir = R*m_segs[i].dir;
}
m_qrot.SetIdentity();
}
return res;
}
if (_params->type==pe_simulation_params::type_id) {
pe_simulation_params *params = (pe_simulation_params*)_params;
if (!is_unused(params->gravity)) m_gravity = params->gravity;
if (!is_unused(params->damping)) m_damping = params->damping;
if (!is_unused(params->maxTimeStep)) m_maxAllowedStep = params->maxTimeStep;
if (!is_unused(params->minEnergy)) m_Emin = params->minEnergy;
return 1;
}
if (_params->type==pe_params_rope::type_id) {
pe_params_rope *params = (pe_params_rope*)_params;
int i;
if (!is_unused(params->length)) m_length = params->length;
if (!is_unused(params->mass)) m_mass = params->mass;
if (!is_unused(params->collDist)) m_collDist = params->collDist;
if (!is_unused(params->surface_idx)) m_surface_idx = params->surface_idx;
if (!is_unused(params->friction)) m_friction = params->friction;
if (!is_unused(params->nSegments)) {
if (params->nSegments>m_nSegs) {
if (m_segs) delete[] m_segs;
m_segs = new rope_segment[params->nSegments+1];
memset(m_segs, 0, (params->nSegments+1)*sizeof(rope_segment));
float seglen = m_length/params->nSegments;
for(i=0;i<=params->nSegments;i++)
(m_segs[i].pt = m_pos).z -= seglen*i;
}
m_nSegs = params->nSegments;
}
if (!is_unused(params->pPoints) && params->pPoints)
for(i=0;i<=m_nSegs;i++) m_segs[i].pt = params->pPoints[i];
if (!is_unused(params->pVelocities) && params->pVelocities)
for(i=0;i<=m_nSegs;i++) m_segs[i].vel = params->pVelocities[i];
if (m_idConstraint && m_pTiedTo[m_iConstraintClient]) {
pe_action_remove_constraint arc;
arc.idConstraint = m_idConstraint;
m_pTiedTo[m_iConstraintClient]->Action(&arc);
m_idConstraint = 0;
}
for(i=0;i<2;i++) if (m_pTiedTo[i]) {
if (m_pTiedTo[i]->m_iSimClass==7)
m_pTiedTo[i] = 0;
else
m_pTiedTo[i]->Awake();
}
for(i=0;i<2;i++) if (!is_unused(params->pEntTiedTo[i])) {
if (m_pTiedTo[i]) m_pTiedTo[i]->Release();
m_pTiedTo[i] = params->pEntTiedTo[i]==WORLD_ENTITY ? &g_StaticPhysicalEntity :
(params->pEntTiedTo[i] ? ((CPhysicalPlaceholder*)params->pEntTiedTo[i])->GetEntity() : 0);
if (!is_unused(params->idPartTiedTo[i])) {
for(m_iTiedPart[i]=0; m_iTiedPart[i]<m_pTiedTo[i]->m_nParts &&
params->idPartTiedTo[i]!=m_pTiedTo[i]->m_parts[m_iTiedPart[i]].id; m_iTiedPart[i]++);
if (m_iTiedPart[i]>=m_pTiedTo[i]->m_nParts)
m_iTiedPart[i] = 0;
}
if (m_pTiedTo[i]) {
RigidBody *pbody = m_pTiedTo[i]->GetRigidBody(m_iTiedPart[i]);
if (!is_unused(params->ptTiedTo[i]))
m_ptTiedLoc[i] = (params->ptTiedTo[i]-pbody->pos)*pbody->q;
else if (!is_unused(params->pEntTiedTo[i]) || !is_unused(params->idPartTiedTo[i]))
m_ptTiedLoc[i] = (m_segs[m_nSegs*i].pt-pbody->pos)*pbody->q;
m_pTiedTo[i]->AddRef();
}
}
m_bAwake = 1;
m_nSlowFrames = 0;
if (m_pTiedTo[0] && (m_pTiedTo[0]==this || m_pTiedTo[0]->m_iSimClass==3 || m_pTiedTo[0]->GetType()==PE_ROPE || m_pTiedTo[0]->GetType()==PE_SOFT) ||
m_pTiedTo[1] && (m_pTiedTo[1]==this || m_pTiedTo[1]->m_iSimClass==3 || m_pTiedTo[1]->GetType()==PE_ROPE || m_pTiedTo[1]->GetType()==PE_SOFT))
{ // rope cannot be attached to such objects
if (m_pTiedTo[0]) m_pTiedTo[0]->Release();
if (m_pTiedTo[1]) m_pTiedTo[1]->Release();
m_pTiedTo[0] = 0; m_pTiedTo[1] = 0;
return 0;
}
if (m_pTiedTo[0] && m_pTiedTo[1]) {
pe_action_add_constraint aac;
m_iConstraintClient = isneg(m_pTiedTo[0]->GetMassInv()-m_pTiedTo[1]->GetMassInv());
for(i=0;i<2;i++) {
RigidBody *pbody = m_pTiedTo[m_iConstraintClient^i]->GetRigidBody(m_iTiedPart[m_iConstraintClient^i]);
aac.pt[i] = pbody->pos + pbody->q*m_ptTiedLoc[m_iConstraintClient^i];
aac.partid[i] = m_pTiedTo[m_iConstraintClient^i]->m_parts[m_iTiedPart[m_iConstraintClient^i]].id;
}
aac.pBuddy = m_pTiedTo[m_iConstraintClient^1];
aac.pConstraintEntity = this;
m_idConstraint = m_pTiedTo[m_iConstraintClient]->Action(&aac);
}
return 1;
}
return 0;
}
int CRopeEntity::GetParams(pe_params *_params)
{
int res;
if (res = CPhysicalEntity::GetParams(_params))
return res;
if (_params->type==pe_simulation_params::type_id) {
pe_simulation_params *params = (pe_simulation_params*)_params;
params->gravity = m_gravity;
params->damping = m_damping;
params->maxTimeStep = m_maxAllowedStep;
params->minEnergy = m_Emin;
return 1;
}
if (_params->type==pe_params_rope::type_id) {
pe_params_rope *params = (pe_params_rope*)_params;
params->length = m_length;
params->mass = m_mass;
params->nSegments = m_nSegs;
params->collDist = m_collDist;
params->surface_idx = m_surface_idx;
params->friction = m_friction;
params->pPoints = &m_segs[0].pt;
params->pVelocities = &m_segs[0].vel;
params->iStride = sizeof(rope_segment);
for(int i=0;i<2;i++) if (params->pEntTiedTo[i] = m_pTiedTo[i]) {
if (m_pTiedTo[i]==&g_StaticPhysicalEntity)
params->pEntTiedTo[i] = WORLD_ENTITY;
params->idPartTiedTo[i] = m_pTiedTo[i]->m_parts[m_iTiedPart[i]].id;
RigidBody *pbody = m_pTiedTo[i]->GetRigidBody(m_iTiedPart[i]);
params->ptTiedTo[i] = pbody->pos + pbody->q*m_ptTiedLoc[i];
}
return 1;
}
return 0;
}
int CRopeEntity::GetStatus(pe_status *_status)
{
int res;
if (res = CPhysicalEntity::GetStatus(_status)) {
if (_status->type==pe_status_caps::type_id) {
pe_status_caps *status = (pe_status_caps*)_status;
status->bCanAlterOrientation = 1;
}
return res;
}
if (_status->type==pe_status_rope::type_id) {
pe_status_rope *status = (pe_status_rope*)_status;
status->nSegments = m_nSegs;
int i;
if (!is_unused(status->pPoints) && status->pPoints)
for(i=0;i<=m_nSegs;i++) status->pPoints[i] = m_segs[i].pt;
if (!is_unused(status->pVelocities) && status->pVelocities)
for(i=0;i<=m_nSegs;i++) status->pVelocities[i] = m_segs[i].vel;
return 1;
}
return 0;
}
int CRopeEntity::Action(pe_action *_action)
{
int res,i,j;
if (res = CPhysicalEntity::Action(_action))
return res;
if (_action->type==pe_action_impulse::type_id) {
pe_action_impulse *action = (pe_action_impulse*)_action;
if (!is_unused(action->ipart)) i = action->ipart;
else if (!is_unused(action->partid)) i = action->partid;
else if (!is_unused(action->point)) {
for(j=1,i=0;j<=m_nSegs;j++) if ((m_segs[j].pt-action->point).len2()<(m_segs[i].pt-action->point).len2())
i=j;
if ((m_segs[i].pt-action->point).len2()>sqr(m_collDist*3) &&
(i==0 || (m_segs[i].pt-m_segs[i-1].pt^action->point-m_segs[i-1].pt).len2() > sqr(m_collDist)*(m_segs[i].pt-m_segs[i-1].pt).len2()))
return 0;
} else
return 0;
if ((unsigned int)i>(unsigned int)m_nSegs)
return 0;
m_segs[i].vel_ext += action->impulse*((m_nSegs+1)/m_mass);
m_bAwake = 1; m_nSlowFrames = 0;
return 1;
}
if (_action->type==pe_action_reset::type_id) {
for(i=0;i<=m_nSegs;i++) {
m_segs[i].vel.zero();
if (m_segs[i].pContactEnt) {
m_segs[i].pContactEnt->Release();
m_segs[i].pContactEnt = 0;
}
}
return 1;
}
return 0;
}
void CRopeEntity::StartStep(float time_interval)
{
m_timeStepPerformed = 0;
m_timeStepFull = time_interval;
}
float CRopeEntity::GetMaxTimeStep(float time_interval)
{
if (m_timeStepPerformed > m_timeStepFull-0.001f)
return time_interval;
return min(min(m_timeStepFull-m_timeStepPerformed,m_maxAllowedStep),time_interval);
}
int __ropeframe = 0;
int CRopeEntity::Step(float time_interval)
{
if (m_nSegs<=0 || !m_bAwake)
return 1;
int i;
for(i=0;i<=m_nSegs;i++) if (m_segs[i].pContactEnt && m_segs[i].pContactEnt->m_iSimClass==7)
m_segs[i].pContactEnt = 0;
for(i=0;i<2;i++) if (m_pTiedTo[i] && m_pTiedTo[i]->m_iSimClass==7)
m_pTiedTo[i] = 0;
if (m_timeStepPerformed > m_timeStepFull-0.001f)
return 1;
m_timeStepPerformed += time_interval;
FUNCTION_PROFILER( GetISystem(),PROFILE_PHYSICS );
PHYS_ENTITY_PROFILER
__ropeframe++;
float seglen=m_length/m_nSegs,seglen2=sqr(seglen), rseglen=m_nSegs/m_length,rseglen2=sqr(rseglen),Ebefore;
int iDir,iStart,iEnd,iter,bStretched,bHasContacts=0;
vectorf dir,ptend[2],sz;
float len2,diff,a,b,r2,r2new,pAp,vmax,k,E,damping=max(0.0f,1.0f-m_damping*time_interval);
for(i=0;i<=m_nSegs;i++) {
m_segs[i].pt += m_segs[i].vel*time_interval;
m_segs[i].vel += m_gravity*time_interval;
}
for(i=0;i<2;i++) if (m_pTiedTo[i]) {
RigidBody *pbody = m_pTiedTo[i]->GetRigidBody(m_iTiedPart[i]);
m_segs[m_nSegs*i].pt = ptend[i] = pbody->pos + pbody->q*m_ptTiedLoc[i];
m_segs[m_nSegs*i].vel = pbody->v + (pbody->w^ptend[i]-pbody->pos);
}
if (m_pTiedTo[0] && m_pTiedTo[1] && (ptend[1]-ptend[0]).len2()>sqr(m_length*0.99f)) {
float newlen=(ptend[1]-ptend[0]).len(), newseglen=newlen/m_nSegs;
dir = (ptend[1]-ptend[0]).normalized();
for(i=1;i<m_nSegs;i++) {
m_segs[i].dir = dir;
m_segs[i].pt = ptend[0] + m_segs[i].dir*(newseglen*i);
}
m_bAwake = m_pTiedTo[0]->GetStatus(&pe_status_awake()) | m_pTiedTo[1]->GetStatus(&pe_status_awake());
m_BBox[0].x = min(m_segs[0].pt.x,m_segs[m_nSegs].pt.x); m_BBox[1].x = max(m_segs[0].pt.x,m_segs[m_nSegs].pt.x);
m_BBox[0].y = min(m_segs[0].pt.y,m_segs[m_nSegs].pt.y); m_BBox[1].y = max(m_segs[0].pt.y,m_segs[m_nSegs].pt.y);
m_BBox[0].z = min(m_segs[0].pt.z,m_segs[m_nSegs].pt.z); m_BBox[1].z = max(m_segs[0].pt.z,m_segs[m_nSegs].pt.z);
a = max(max(m_BBox[1].x-m_BBox[0].x,m_BBox[1].y-m_BBox[0].y),m_BBox[1].z-m_BBox[0].z)*0.01f+m_collDist*2;
m_BBox[0] -= vectorf(a,a,a); m_BBox[1] += vectorf(a,a,a);
if (m_flags & pef_traceable)
m_pWorld->RepositionEntity(this,1);
return 1;
}
// first, ensure that all vertices have distance between them equal to seglen
iter=300;
iDir = m_pTiedTo[1] && !m_pTiedTo[0] ? 1:-1;
do {
iDir = -iDir;
iStart = m_nSegs & iDir>>31;
iEnd = m_nSegs & -iDir>>31;
for(i=iStart;i!=iEnd;i+=iDir) {
dir = m_segs[i+iDir].pt-m_segs[i].pt; len2 = dir.len2();
diff = fabs_tpl(len2-seglen2);
if (bStretched = (diff>seglen2*0.01f)) {
if (diff<seglen2*0.2f) { // use 3 terms of 1/sqrt(x) Taylor series expansion
k = len2*rseglen2; k = 1.875f-(1.25f-0.375f*k)*k;
} else
k = seglen/sqrt_tpl(len2);
m_segs[i+iDir].pt = m_segs[i].pt + dir*k;
iter--;
} else k = 1.0f;
m_segs[i+(iDir>>31)].dir = dir*(k*rseglen);
}
if (m_pTiedTo[0]) m_segs[0].pt = ptend[0];
if (m_pTiedTo[1]) m_segs[m_nSegs].pt = ptend[1];
} while(m_pTiedTo[iDir+1>>1] && bStretched && iter>0);
m_BBox[0] = m_BBox[1] = m_segs[0].pt;
for(i=0;i<=m_nSegs;i++) {
(m_segs[i].vel += m_segs[i].vel_ext) *= damping;
m_segs[i].vel_ext.zero();
m_segs[i].bRecalcDir = 0;
m_BBox[0].x = min(m_BBox[0].x, m_segs[i].pt.x); m_BBox[1].x = max(m_BBox[1].x, m_segs[i].pt.x);
m_BBox[0].y = min(m_BBox[0].y, m_segs[i].pt.y); m_BBox[1].y = max(m_BBox[1].y, m_segs[i].pt.y);
m_BBox[0].z = min(m_BBox[0].z, m_segs[i].pt.z); m_BBox[1].z = max(m_BBox[1].z, m_segs[i].pt.z);
}
a = max(max(m_BBox[1].x-m_BBox[0].x,m_BBox[1].y-m_BBox[0].y),m_BBox[1].z-m_BBox[0].z)*0.01f+m_collDist*2;
m_BBox[0] -= vectorf(a,a,a); m_BBox[1] += vectorf(a,a,a);
if (m_flags & rope_collides) {
CPhysicalEntity **pentlist;
int j,iseg,nEnts,nCheckParts,nLocChecks,iend;
box boxrope,boxpart;
vectorf center,ptres[2],rotax,n;
float angle,dist2,t,cost,sint;
struct check_part {
vectorf offset;
matrix3x3f R;
float scale;
box bbox;
CPhysicalEntity *pent;
int ipart;
};
check_part checkParts[20];
CRayGeom aray; aray.m_iCollPriority = 10;
intersection_params ip;
geom_contact *pcontact;
CPhysicalEntity *pent;
geom_world_data gwd;
g_Overlapper.Init();
boxrope.size = (m_BBox[1]-m_BBox[0])*0.5f;
center = (m_BBox[0]+m_BBox[1])*0.5f;
ip.bStopAtFirstTri = true;
ip.iUnprojectionMode = 1;
nEnts = m_pWorld->GetEntitiesAround(m_BBox[0],m_BBox[1], pentlist,
(m_flags & rope_collides_with_terrain ? ent_terrain:0) |
ent_static|ent_sleeping_rigid|ent_rigid|ent_living|ent_sort_by_mass|ent_ignore_noncolliding|ent_triggers, this);
for(i=j=nCheckParts=0;i<nEnts;i++) if (pentlist[i]!=this)
for(j=0;j<pentlist[i]->m_nParts;j++) {
checkParts[nCheckParts].offset = pentlist[i]->m_pos+pentlist[i]->m_qrot*pentlist[i]->m_parts[j].pos;
//(pentlist[i]->m_qrot*pentlist[i]->m_parts[j].q).getmatrix(boxrope.Basis); //Q2M_IVO
boxrope.Basis = matrix3x3f(pentlist[i]->m_qrot*pentlist[i]->m_parts[j].q);
boxrope.center = (center-checkParts[nCheckParts].offset)*boxrope.Basis;
if (pentlist[i]->m_parts[j].pPhysGeomProxy->pGeom->GetType()!=GEOM_HEIGHTFIELD) {
pentlist[i]->m_parts[j].pPhysGeomProxy->pGeom->GetBBox(&checkParts[nCheckParts].bbox);
checkParts[nCheckParts].bbox.center *= pentlist[i]->m_parts[j].scale;
checkParts[nCheckParts].bbox.size *= pentlist[i]->m_parts[j].scale;
} else
checkParts[nCheckParts].bbox = boxrope;
boxrope.bOriented++;
if (box_box_overlap_check(&boxrope,&checkParts[nCheckParts].bbox)) {
checkParts[nCheckParts].pent = pentlist[i];
checkParts[nCheckParts].ipart = j;
checkParts[nCheckParts].R = boxrope.Basis;
checkParts[nCheckParts].scale = pentlist[i]->m_parts[j].scale;
pentlist[i]->m_parts[j].pPhysGeomProxy->pGeom->PrepareForRayTest(
pentlist[i]->m_parts[j].scale==1.0f ? seglen:seglen/pentlist[i]->m_parts[j].scale);
if (++nCheckParts==sizeof(checkParts)/sizeof(checkParts[0]))
goto enoughgeoms;
}
} enoughgeoms:
if (m_pTiedTo[0] && m_pTiedTo[1])
iDir = isneg(m_pTiedTo[1]->GetRigidBody(m_iTiedPart[1])->Minv-m_pTiedTo[0]->GetRigidBody(m_iTiedPart[0])->Minv);
else
iDir = iszero((intptr_t)m_pTiedTo[0]);
iDir = 1-iDir*2;
iStart = m_nSegs & iDir>>31;
iEnd = m_nSegs & -iDir>>31;
for(i=iStart;i!=iEnd;i+=iDir) {
iseg = i+(iDir>>31);
if (pent=m_segs[iseg].pContactEnt) {
//(pent->m_qrot*pent->m_parts[m_segs[iseg].iContactPart].q).getmatrix(gwd.R); //Q2M_IVO
gwd.R = matrix3x3f(pent->m_qrot*pent->m_parts[m_segs[iseg].iContactPart].q);
gwd.offset = pent->m_pos + pent->m_qrot*pent->m_parts[m_segs[iseg].iContactPart].pos;
gwd.scale = pent->m_parts[m_segs[iseg].iContactPart].scale;
if (!m_segs[iseg].bRecheckContact &&
pent->m_parts[m_segs[iseg].iContactPart].pPhysGeomProxy->pGeom->FindClosestPoint(&gwd, m_segs[iseg].iPrim,m_segs[iseg].iFeature,
m_segs[i+iDir].pt,m_segs[i].pt, ptres)>=0 &&
(dist2=(n=ptres[1]-ptres[0]).len2())<sqr(m_collDist*2) && // drop contact when gap becomes too big
sqr_signed(m_segs[iseg].vreq=n*m_segs[iseg].ncontact)>n.len2()*sqr(0.75f)) // drop contact if normal changes abruptly
{
n.normalize();
m_segs[i].tcontact = (ptres[1]-m_segs[iseg].pt).len()*rseglen;
if (dist2<sqr(m_collDist*0.85f)) { // reinforce the distance
t = (iDir>>31&1) + m_segs[i].tcontact*iDir; // 1.0-t for iDir==-1
j = isneg(t-0.1f); t += j; j = -j & iDir;
if ((unsigned int)i-j<=(unsigned int)m_nSegs) {
rotax = (m_segs[i+iDir-j].pt-m_segs[i-j].pt^n).normalized();
angle = (m_collDist-sqrt_tpl(dist2))/(t*seglen);
m_segs[i+iDir-j].pt = m_segs[i+iDir-j].pt.rotated(m_segs[i-j].pt, rotax, cos_tpl(angle),sin_tpl(angle));
m_segs[i+iDir-j].bRecalcDir = m_segs[max(0,i+iDir-j-1)].bRecalcDir = 1;
}
m_segs[iseg].vreq = 0;
} else
m_segs[iseg].vreq = (m_collDist-m_segs[iseg].vreq)*10.0f;
m_segs[i].ncontact = n;
RigidBody *pbody = m_segs[iseg].pContactEnt->GetRigidBody(m_segs[iseg].iContactPart);
m_segs[iseg].vcontact = pbody->v+(pbody->w^ptres[0]-pbody->pos);
bHasContacts = 1;
} else {
m_segs[iseg].pContactEnt->Release();
m_segs[iseg].pContactEnt = 0;
}
}
if (!m_segs[iseg].pContactEnt) for(j=nLocChecks=0;j<nCheckParts && nLocChecks<6;j++) {
aray.m_ray.origin = (m_segs[i].pt-checkParts[j].offset)*checkParts[j].R;
aray.m_ray.dir = (m_segs[i+iDir].pt-checkParts[j].offset)*checkParts[j].R-aray.m_ray.origin;
if (box_ray_overlap_check(&checkParts[j].bbox,&aray.m_ray)) {
ip.centerOfRotation = aray.m_ray.origin;
gwd.offset.zero(); gwd.R.SetIdentity(); gwd.scale=checkParts[j].scale;
if (checkParts[j].pent->m_parts[checkParts[j].ipart].pPhysGeomProxy->pGeom->Intersect(&aray,&gwd,0,&ip,pcontact) &&
pcontact->iUnprojMode==1)
{
if (pcontact->t>(real)0.5) {
pcontact->t=(real)0.5; m_segs[iseg].bRecheckContact=1;
} else
m_segs[iseg].bRecheckContact=0;
if (m_segs[iseg].pContactEnt)
m_segs[iseg].pContactEnt->Release();
m_segs[iseg].pContactEnt = 0;
diff = m_segs[iseg].tcontact = (pcontact->pt-aray.m_ray.origin).len();
m_segs[iseg].tcontact = m_segs[iseg].tcontact*iDir-seglen*(iDir>>31); // flip tcontact when iDir is -1
iend = -iseg>>31 & 1;
if ((unsigned int)(iseg-1)>=(unsigned int)(m_nSegs-2) && m_pTiedTo[iend] && isneg(m_segs[iseg].tcontact*rseglen-0.5f)^iend)
continue; // ignore collisions too close to tied ends
(m_segs[iseg].pContactEnt = checkParts[j].pent)->AddRef();
m_segs[iseg].iContactPart = checkParts[j].ipart;
rotax = checkParts[j].R*-pcontact->dir;
if (m_collDist > diff*0.25f) {
if ((unsigned int)(i-iDir)>(unsigned int)m_nSegs)
continue;
// the contact is too close to the segment start (requires >15 deg. gap unproj), rotate start point to get the safe gap
float tgap = m_collDist/seglen;
cost = cos_tpl(tgap); sint = sin_tpl(tgap);
m_segs[i].pt = m_segs[i].pt.rotated(m_segs[i-iDir].pt, rotax, cost,sint);
m_segs[i+iDir].pt = m_segs[i+iDir].pt.rotated(m_segs[i-iDir].pt, rotax, cost,sint);
m_segs[i].bRecalcDir = m_segs[max(0,i-1)].bRecalcDir = 1;
} else
pcontact->t += m_collDist/diff;
cost = cos_tpl(pcontact->t); sint = sin_tpl(pcontact->t);
m_segs[iseg].ncontact = checkParts[j].R*(pcontact->n.normalized().rotated(pcontact->dir,cost,-sint));
m_segs[iseg].tcontact *= rseglen;
m_segs[i+iDir].pt = m_segs[i+iDir].pt.rotated(m_segs[i].pt, rotax, cost,sint);
aray.m_ray.dir = (m_segs[i+iDir].pt-checkParts[j].offset)*checkParts[j].R-aray.m_ray.origin;
m_segs[iseg].iPrim = pcontact->iPrim[0];
m_segs[iseg].iFeature = pcontact->iFeature[0];
/*m_segs[iseg].friction[0] = 0.5f*max(0.0f, m_pWorld->m_FrictionTable[m_surface_idx&NSURFACETYPES-1] +
m_pWorld->m_FrictionTable[pcontact->id[0]&NSURFACETYPES-1]);
m_segs[iseg].friction[1] = 0.5f*max(0.0f, m_pWorld->m_DynFrictionTable[m_surface_idx&NSURFACETYPES-1] +
m_pWorld->m_DynFrictionTable[pcontact->id[0]&NSURFACETYPES-1]);*/
m_segs[iseg].friction[0] = m_segs[iseg].friction[1] = m_friction;
RigidBody *pbody = m_segs[iseg].pContactEnt->GetRigidBody(m_segs[iseg].iContactPart);
m_segs[iseg].vcontact = pbody->v+(pbody->w^pcontact->pt-pbody->pos);
m_segs[i+iDir].bRecalcDir = m_segs[max(0,i+iDir-1)].bRecalcDir = 1;
m_segs[iseg].vreq = 0;
bHasContacts = 1;
//break;
}
//nLocChecks++;
}
}
}
for(i=0;i<m_nSegs;i++) if (m_segs[i].bRecalcDir)
m_segs[i].dir = (m_segs[i+1].pt-m_segs[i].pt).normalized();
}
for(i=0,Ebefore=0;i<=m_nSegs;i++)
Ebefore += m_segs[i].vel.len2();
if (bHasContacts) {
int iter,bBounced;
float vrel,dPtang;
vectorf dp;
for(i=0;i<m_nSegs;i++)
m_segs[i].kdP = 0.5f;
if (m_pTiedTo[0]) m_segs[0].kdP=0.0f;
if (m_pTiedTo[1]) m_segs[m_nSegs-1].kdP=1.0f;
// solve for velocities using relaxation solver with friction
iter = 200;
do {
for(i=bBounced=0;i<m_nSegs;i++) {
if (fabsf(vrel=(m_segs[i+1].vel-m_segs[i].vel)*m_segs[i].dir) > seglen*0.005f) {
m_segs[i].vel += m_segs[i].dir*(vrel*m_segs[i].kdP);
m_segs[i+1].vel -= m_segs[i].dir*(vrel*(1.0f-m_segs[i].kdP));
bBounced++;
}
if (m_segs[i].pContactEnt) {
dp = m_segs[i].vel*(1.0f-m_segs[i].tcontact)+m_segs[i+1].vel*m_segs[i].tcontact-m_segs[i].vcontact;
if ((vrel=dp*m_segs[i].ncontact-m_segs[i].vreq) < -seglen*0.005f) {
if (m_segs[i].friction[0]>0.01f) {
m_segs[i].dP -= dPtang=sqrt_tpl(max(0.0f,dp.len2()-sqr(vrel)));
if (m_segs[i].dP-vrel*m_segs[i].friction[0] < 0) { // friction cannot stop sliding
dp += (dp-m_segs[i].ncontact*vrel)*((m_segs[i].dP-vrel*m_segs[i].friction[1])/dPtang); // remove part of dp that friction cannot stop
dp *= vrel/(m_segs[i].ncontact*dp); // apply impulse along dp so that it stops normal component
m_segs[i].dP = 0;
} else
m_segs[i].dP -= vrel*m_segs[i].friction[0];
} else
dp = m_segs[i].ncontact*vrel;
m_segs[i].vel -= dp*((1.0f-m_segs[i].tcontact)*m_segs[i].kdP);
m_segs[i+1].vel -= dp*(m_segs[i].tcontact*(1.0f-m_segs[i].kdP));
bBounced++;
}
}
}
} while (bBounced && --iter);
} else {
// solve for velocities using conjugate gradient
for(i=0,r2=0;i<m_nSegs;i++) {
r2 += sqr(m_segs[i].dP = m_segs[i].r = (m_segs[i+1].vel-m_segs[i].vel)*m_segs[i].dir);
m_segs[i].cosnext = m_segs[i].dir*m_segs[i+1].dir;
m_segs[i].kdP = 2.0f;
m_segs[i].P = 0;
}
if (m_pTiedTo[0]) m_segs[0].kdP=1.0f;
if (m_pTiedTo[1]) m_segs[m_nSegs-1].kdP=1.0f;
iter = m_nSegs*3;
do {
m_segs[0].dv = m_segs[0].dP*m_segs[0].kdP;
m_segs[1].dv = -m_segs[0].cosnext*m_segs[0].dP;
for(i=1;i<m_nSegs;i++) {
m_segs[i-1].dv -= m_segs[i-1].cosnext*m_segs[i].dP;
m_segs[i].dv += m_segs[i].dP*m_segs[i].kdP;
m_segs[i+1].dv = -m_segs[i].cosnext*m_segs[i].dP;
}
for(i=0,pAp=0;i<m_nSegs;i++)
pAp += m_segs[i].dv*m_segs[i].dP;
if (fabs_tpl(pAp)<1E-10) break;
a = r2/pAp;
for(i=0,r2new=0;i<m_nSegs;i++) {
r2new += sqr(m_segs[i].r -= m_segs[i].dv*a);
m_segs[i].P += m_segs[i].dP*a;
}
if (r2new>r2*500)
break;
b = r2new/r2; r2 = r2new;
for(i=0,vmax=0;i<m_nSegs;i++) {
(m_segs[i].dP*=b) += m_segs[i].r;
vmax = max(vmax,sqr(m_segs[i].r));
}
} while(--iter && vmax>sqr(0.003f));
if (!m_pTiedTo[0]) m_segs[0].vel += m_segs[0].dir*m_segs[0].P;
if (!m_pTiedTo[1]) m_segs[m_nSegs].vel -= m_segs[m_nSegs-1].dir*m_segs[m_nSegs-1].P;
m_segs[1].vel -= m_segs[0].dir*m_segs[0].P;
m_segs[m_nSegs-1].vel += m_segs[m_nSegs-1].dir*m_segs[m_nSegs-1].P;
for(i=1;i<m_nSegs-1;i++) {
m_segs[i].vel += m_segs[i].dir*m_segs[i].P;
m_segs[i+1].vel -= m_segs[i].dir*m_segs[i].P;
}
}
for(i=0,E=0;i<=m_nSegs;i++) E += m_segs[i].vel.len2();
if (E>Ebefore && E>m_Emin) {
k = sqrt_tpl(Ebefore/E);
for(i=0;i<=m_nSegs;i++) m_segs[i].vel*=k;
E = Ebefore;
}
i = -isneg(E-m_Emin*(m_nSegs+1));
m_nSlowFrames = (m_nSlowFrames&i)-i;
if (!(m_bAwake = isneg(m_nSlowFrames-4)))
for(i=iszero((intptr_t)m_pTiedTo[0])^1; i<m_nSegs+iszero((intptr_t)m_pTiedTo[1]); i++)
m_segs[i].vel.zero();
m_pos = m_segs[0].pt;
if (m_flags & pef_traceable)
m_pWorld->RepositionEntity(this,1);
return isneg(m_timeStepFull-m_timeStepPerformed-0.001f);
}
int CRopeEntity::RayTrace(CRayGeom *pRay,geom_contact *&pcontacts)
{
static geom_contact g_RopeContact;
vectorf dp,dir,l,pt;
float t,t1,llen2,raylen=pRay->m_ray.dir*pRay->m_dirn;
int i;
for(i=0;i<m_nSegs;i++) {
dp = pRay->m_ray.origin-m_segs[i].pt;
if ((dp^pRay->m_dirn).len2()<sqr(m_collDist) && inrange((m_segs[i].pt-pRay->m_ray.origin)*pRay->m_dirn, 0.0f,raylen)) {
pt = m_segs[i].pt; break;
}
dir = m_segs[i+1].pt-m_segs[i].pt;
l = dir^pRay->m_dirn; llen2 = l.len2();
t = (dp^pRay->m_dirn)*l; t1 = (dp^dir)*l;
if (sqr(dp*l)<sqr(m_collDist)*llen2 && inrange(t, 0.0f,llen2) && inrange(t1, 0.0f,llen2*raylen)) {
pt = m_segs[i].pt+dir*(t/llen2); break;
}
}
if (i<m_nSegs) {
pcontacts = &g_RopeContact;
pcontacts->pt = pt;
pcontacts->t = (pt-pRay->m_ray.origin)*pRay->m_dirn;
pcontacts->id[0] = m_surface_idx;
pcontacts->iNode[0] = 0;
pcontacts->n = -pRay->m_dirn;
return 1;
}
return 0;
}
int CRopeEntity::GetStateSnapshot(CStream &stm,float time_back,int flags)
{
stm.WriteNumberInBits(SNAPSHOT_VERSION,4);
WritePacked(stm,m_nSegs);
if (m_nSegs>0) for(int i=0; i<=m_nSegs; i++) {
stm.Write(m_segs[i].pt);
if (m_segs[i].vel.len2()>0) {
stm.Write(true);
stm.Write(m_segs[i].vel);
} else stm.Write(false);
}
stm.Write(m_bAwake!=0);
return 1;
}
int CRopeEntity::SetStateFromSnapshot(CStream &stm, int flags)
{
int i,ver=0;
bool bnz;
stm.ReadNumberInBits(ver,4);
if (ver!=SNAPSHOT_VERSION)
return 0;
ReadPacked(stm,i);
if (i!=m_nSegs)
return 0;
if (!(flags & ssf_no_update)) {
if (m_nSegs>0) for(i=0; i<=m_nSegs; i++) {
stm.Read(m_segs[i].pt);
stm.Read(bnz); if (bnz)
stm.Read(m_segs[i].vel);
else
m_segs[i].vel.zero();
if (m_segs[i].pContactEnt) {
m_segs[i].pContactEnt->Release();
m_segs[i].pContactEnt = 0;
}
}
stm.Read(bnz);
m_bAwake = bnz ? 1:0;
for(i=0;i<m_nSegs;i++)
m_segs[i].dir = (m_segs[i+1].pt-m_segs[i].pt).normalized();
m_pos = m_segs[0].pt;
if (m_flags & pef_traceable)
m_pWorld->RepositionEntity(this,1);
} else {
for(i=0;i<=m_nSegs;i++) {
stm.Seek(stm.GetReadPos()+sizeof(vectorf)*8);
stm.Read(bnz); if (bnz)
stm.Seek(stm.GetReadPos()+sizeof(vectorf)*8);
}
stm.Read(bnz);
}
return 1;
}
void CRopeEntity::DrawHelperInformation(void (*DrawLineFunc)(float*,float*), int flags)
{
CPhysicalEntity::DrawHelperInformation(DrawLineFunc,flags);
int i;
if (flags & pe_helper_geometry) for(i=0;i<m_nSegs;i++)
DrawLineFunc(m_segs[i].pt,m_segs[i+1].pt);
if (flags & pe_helper_collisions) for(i=0;i<m_nSegs;i++) if (m_segs[i].pContactEnt) {
vectorf pt = m_segs[i].pt+(m_segs[i+1].pt-m_segs[i].pt)*m_segs[i].tcontact;
DrawLineFunc(pt,pt+m_segs[i].ncontact*m_pWorld->m_vars.maxContactGap*30);
}
}
void CRopeEntity::GetMemoryStatistics(ICrySizer *pSizer)
{
CPhysicalEntity::GetMemoryStatistics(pSizer);
if (GetType()==PE_ROPE)
pSizer->AddObject(this, sizeof(CRopeEntity));
pSizer->AddObject(m_segs, m_nSegs*sizeof(m_segs[0]));
}

76
CryPhysics/ropeentity.h Normal file
View File

@@ -0,0 +1,76 @@
#ifndef ropeentity_h
#define ropeentity_h
struct rope_segment {
~rope_segment() { if (pContactEnt) pContactEnt->Release(); }
vectorf pt;
vectorf vel;
vectorf dir;
vectorf vel_ext;
CPhysicalEntity *pContactEnt;
int iContactPart;
int bRecheckContact;
float tcontact;
vectorf ncontact;
vectorf vcontact;
float vreq;
float friction[2];
int iPrim,iFeature;
int bRecalcDir;
float r,P;
float dP,dv;
float cosnext,kdP;
};
class CRopeEntity : public CPhysicalEntity {
public:
CRopeEntity(CPhysicalWorld *pworld);
virtual ~CRopeEntity();
virtual pe_type GetType() { return PE_ROPE; }
virtual int SetParams(pe_params*);
virtual int GetParams(pe_params*);
virtual int GetStatus(pe_status*);
virtual int Action(pe_action*);
virtual void StartStep(float time_interval);
virtual float GetMaxTimeStep(float time_interval);
virtual int Step(float time_interval);
virtual int Awake(int bAwake=1,int iSource=0);
virtual int IsAwake(int ipart=-1) { return m_bAwake; }
virtual void AlertNeighbourhoodND();
virtual int RayTrace(CRayGeom *pRay, geom_contact *&pcontacts);
enum snapver { SNAPSHOT_VERSION = 8 };
virtual int GetStateSnapshot(CStream &stm, float time_back=0,int flags=0);
virtual int SetStateFromSnapshot(CStream &stm, int flags);
virtual void DrawHelperInformation(void (*DrawLineFunc)(float*,float*), int flags);
virtual void GetMemoryStatistics(ICrySizer *pSizer);
vectorf m_gravity;
float m_damping;
float m_maxAllowedStep;
float m_Emin;
int m_bAwake;
float m_timeStepPerformed,m_timeStepFull;
int m_nSlowFrames;
float m_length;
int m_nSegs;
float m_mass;
float m_collDist;
int m_surface_idx;
float m_friction;
rope_segment *m_segs;
CPhysicalEntity *m_pTiedTo[2];
vectorf m_ptTiedLoc[2];
int m_iTiedPart[2];
int m_idConstraint;
int m_iConstraintClient;
};
#endif

View File

@@ -0,0 +1,533 @@
#include "stdafx.h"
#include "utils.h"
#include "primitives.h"
#include "unprojectionchecks.h"
#define UPDATE_IDBEST(tbest,newid) \
(idbest&=~-bBest) |= (newid)&-bBest; \
(tbest.x*=bBest^1) += tsin.x*bBest; \
(tbest.y*=bBest^1) += tsin.y*bBest
int tri_tri_rot_unprojection(unprojection_mode *pmode, const triangle *ptri1,int iFeature1, const triangle *ptri2,int iFeature2,
contact *pcontact, geom_contact_area *parea)
{
const triangle *ptri[2] = { ptri1,ptri2 };
vectorr pt,ptz[2][3],ptx[2][3],pty[2][3],rotax,pt0,pt1,edge0,edge1,n0z,n0x,n0y,ptz0,ptx0,pty0,n,pt0_rot,
pt1_rot,edge0_rot,ptz1,ptx1,pty1,dir0,dir1,norm[2];
quotient tsin,tcos,tmin(pmode->tmax,1),t0,t1;
real kcos,ksin,k,a,b,c,d,sg0,sg1;
int itri,i,j,j1,bContact,bBest,idbest=-1,imask=iFeature2<<8 | iFeature1;
// compute components for vec.rot(t) = vecz + vecx*cos(t) + vecy*sin(t)
for(itri=0,rotax=pmode->dir;itri<2;itri++,rotax*=-1) for(i=0;i<3;i++) {
pt = ptri[itri]->pt[i]-pmode->center;
ptz[itri][i] = rotax*(pt*rotax); ptx[itri][i] = pt-ptz[itri][i]; pty[itri][i] = rotax^ptx[itri][i];
}
// vertex-face contacts, (p[i].rot(t)-origin)*n = 0; -t for the 2nd triangle
for(itri=0;itri<2;itri++) for(i=0;i<3;i++) if ((0x40<<(itri<<3) | (0x80|i)<<((itri^1)<<3))!=imask) {
kcos = ptx[itri^1][i]*ptri[itri]->n; ksin = pty[itri^1][i]*ptri[itri]->n;
k = (ptz[itri^1][i]-ptri[itri]->pt[0]+pmode->center)*ptri[itri]->n;
a = sqr(ksin)+sqr(kcos); b = ksin*k; c = sqr(k)-sqr(kcos); d = b*b-a*c;
if (d>=0) {
d = sqrt_tpl(d); tsin.set(-b-d,a);
for(j=0;j<2;j++,tsin.x+=d*2)
if (isneg(fabs_tpl(tsin.x*2-tsin.y)-tsin.y) & // tsin in (0..1)
isneg((ksin*tsin.x+k*tsin.y)*kcos)) // tcos in (0..1) (=eliminate foreign root)
{
tcos.set(sqrt_tpl(sqr(tsin.y)-sqr(tsin.x)),tsin.y);
pt = ptx[itri^1][i]*tcos.x + pty[itri^1][i]*tsin.x + (ptz[itri^1][i]+pmode->center)*tsin.y;
bContact = // point is inside itri
isneg((pt-ptri[itri]->pt[0]*tsin.y ^ ptri[itri]->pt[1]-ptri[itri]->pt[0])*ptri[itri]->n) &
isneg((pt-ptri[itri]->pt[1]*tsin.y ^ ptri[itri]->pt[2]-ptri[itri]->pt[1])*ptri[itri]->n) &
isneg((pt-ptri[itri]->pt[2]*tsin.y ^ ptri[itri]->pt[0]-ptri[itri]->pt[2])*ptri[itri]->n);
// additionally check that triangles don't intersect during contact
pt = ptx[itri^1][inc_mod3[i]]*tcos.x + pty[itri^1][inc_mod3[i]]*tsin.x + (ptz[itri^1][inc_mod3[i]] +
pmode->center - ptri[itri]->pt[0])*tsin.y;
sg0 = pt*ptri[itri]->n + pmode->minPtDist*tsin.y;
pt = ptx[itri^1][dec_mod3[i]]*tcos.x + pty[itri^1][dec_mod3[i]]*tsin.x + (ptz[itri^1][dec_mod3[i]] +
pmode->center - ptri[itri]->pt[0])*tsin.y;
sg1 = pt*ptri[itri]->n + pmode->minPtDist*tsin.y;
bContact &= isnonneg(sg0*sg1);
bBest = bContact & isneg(tsin-tmin);
UPDATE_IDBEST(tmin,itri<<2 | i);
}
}
} else { // check if triangles are already separated in their initial state
sg0 = (ptri[itri^1]->pt[inc_mod3[i]]-ptri[itri]->pt[0])*ptri[itri]->n + pmode->minPtDist;
sg1 = (ptri[itri^1]->pt[dec_mod3[i]]-ptri[itri]->pt[0])*ptri[itri]->n + pmode->minPtDist;
bBest = isnonneg(sg0) & isnonneg(sg1); tsin.set(0,1);
UPDATE_IDBEST(tmin,itri<<2 | i);
}
rotax = pmode->dir;
n0z = rotax*(ptri[0]->n*rotax); n0x = ptri[0]->n-n0z; n0y = rotax^n0x;
// edge-edge contacts
// (p0.rot(t)-p1)*(l0.rot(t)^l1) = 0
// p0.rot(t)*(l0.rot(t)^l1) - p1*(l0.rot(t)^l1) = 0;
// l1*(p0^l0).rot(t) + l0.rot(t)*(p1^l1) = 0;
// l1*(p0^l0).rot(t) + l0*(p1^l1).rot(-t) = 0; - this one's just to get symmetrical form
// note that p.rot(t)^l.rot(t)==(p^l).rot(t) only if p is relative to the center of rotation
for(i=0;i<3;i++) {
pt0 = ptri[0]->pt[i]-pmode->center;
edge0 = ptri[0]->pt[inc_mod3[i]]-ptri[0]->pt[i];
pt = pt0^edge0; ptz0 = rotax*(pt*rotax); ptx0 = pt-ptz0; pty0 = rotax^ptx0;
for(j=0;j<3;j++) if ((0xA0|i | (0xA0|j)<<8)!=imask) {
pt1 = ptri[1]->pt[j]-pmode->center;
edge1 = ptri[1]->pt[inc_mod3[j]]-ptri[1]->pt[j];
pt = pt1^edge1; ptz1 = rotax*(pt*rotax); ptx1 = pt-ptz1; pty1 = rotax^ptx1;
kcos = edge1*ptx0+edge0*ptx1; ksin = edge1*pty0-edge0*pty1; k = edge1*ptz0+edge0*ptz1;
a = sqr(ksin)+sqr(kcos); b = ksin*k; c = sqr(k)-sqr(kcos); d = b*b-a*c;
if (d>=0) {
d = sqrt_tpl(d); tsin.set(-b-d,a);
for(j1=0;j1<2;j1++,tsin.x+=d*2)
if (isneg(fabs_tpl(tsin.x*2-tsin.y)-tsin.y) & // tsin in (0..1)
isneg((ksin*tsin.x+k*tsin.y)*kcos)) // tcos in (0..1) (=eliminate foreign root)
{
tcos.set(sqrt_tpl(sqr(tsin.y)-sqr(tsin.x)),tsin.y);
pt0_rot = ptx[0][i]*tcos.x + pty[0][i]*tsin.x + ptz[0][i]*tsin.y;
pt1_rot = ptx[0][inc_mod3[i]]*tcos.x + pty[0][inc_mod3[i]]*tsin.x + ptz[0][inc_mod3[i]]*tsin.y;
edge0_rot = pt1_rot-pt0_rot;
n = edge0_rot^edge1; pt = pt1*tsin.y-pt0_rot;
t0.set((pt^edge1)*n, n.len2());
t1.set((pt^edge0_rot)*n, t0.y*tsin.y);
bContact = isneg(fabs_tpl(t0.x*2-t0.y)-t0.y) & isneg(fabs_tpl(t1.x*2-t1.y)-t1.y);
// additionally check that triangles don't intersect during contact
dir0 = (n0z*tsin.y+n0x*tcos.x+n0y*tsin.x)^edge0_rot;
dir1 = ptri[1]->n^edge1;
bContact &= isneg((dir0*n)*(dir1*n));
bBest = bContact & isneg(tsin-tmin);
UPDATE_IDBEST(tmin,i<<2 | j | 0x80);
}
}
} else { // check if triangles are already separated in their initial state
edge1 = ptri[1]->pt[inc_mod3[j]]-ptri[1]->pt[j]; n = edge0^edge1;
dir0 = ptri[0]->n^edge0; dir1 = ptri[1]->n^edge1;
bBest = isneg((dir0*n)*(dir1*n)); tsin.set(0,1);
// additionally check that edges intersection point will not move inside the 2nd triangle during unprojection
bBest &= isneg(dir1*(pmode->dir ^ (ptri[0]->pt[i]-pmode->center)*n.len2() + edge0*((ptri[1]->pt[j]-ptri[0]->pt[i]^edge1)*n)));
UPDATE_IDBEST(tmin,i<<2 | j | 0x80);
}
}
if (idbest==-1)
return 0;
if (idbest & 0x80) {
i = idbest>>2 & 3; j = idbest & 3;
pcontact->t = tmin.val();
pcontact->taux = sqrt_tpl(1-sqr(pcontact->t));
pt0_rot = ptx[0][i]*pcontact->taux + pty[0][i]*pcontact->t + ptz[0][i] + pmode->center;
pt1_rot = ptx[0][inc_mod3[i]]*pcontact->taux + pty[0][inc_mod3[i]]*pcontact->t + ptz[0][inc_mod3[i]] + pmode->center;
edge0_rot = pt1_rot-pt0_rot;
edge1 = ptri[1]->pt[inc_mod3[j]]-ptri[1]->pt[j];
pt = ptri[1]->pt[j]-pt0_rot; n = edge0_rot ^ edge1;
t0.set((pt^edge1)*n, n.len2());
pcontact->pt = pt0_rot + edge0_rot*t0.val();
pcontact->n = n*sgnnz((ptri2->n^edge1)*n);
pcontact->iFeature[0] = 0xA0 | i;
pcontact->iFeature[1] = 0xA0 | j;
} else {
itri = idbest>>2; i = idbest & 3;
pcontact->t = tmin.val();
pcontact->taux = sqrt_tpl(1-sqr(pcontact->t));
pcontact->pt = ptz[itri^1][i] + ptx[itri^1][i]*max(pcontact->taux,(real)(itri^1)) + pty[itri^1][i]*(pcontact->t*itri) + pmode->center;
norm[0] = n0z+n0x*pcontact->taux+n0y*pcontact->t; norm[1] = -ptri[1]->n;
pcontact->n = norm[itri];
pcontact->iFeature[itri] = 0x40;
pcontact->iFeature[itri^1] = 0x80 | i;
}
return 1;
}
int ray_tri_rot_unprojection(unprojection_mode *pmode, const ray *pray,int iFeature1, const triangle *ptri,int iFeature2,
contact *pcontact, geom_contact_area *parea)
{
vectorr pt,ptz[2],ptx[2],pty[2],rotax=pmode->dir,edge1,ptz0,ptx0,pty0,pt1,pt0_rot,pt1_rot,edge0_rot,ptz1,ptx1,pty1,n;
quotient tsin,tcos,tmin(pmode->tmax,1),t0,t1;
real kcos,ksin,k,a,b,c,d;
int i,j,bContact,bBest,idbest=-1,imask=iFeature2<<8 | iFeature1;
pt = pray->origin-pmode->center;
ptz[0] = rotax*(pt*rotax); ptx[0] = pt-ptz[0]; pty[0] = rotax^ptx[0];
pt += pray->dir;
ptz[1] = rotax*(pt*rotax); ptx[1] = pt-ptz[1]; pty[1] = rotax^ptx[1];
// ray end - triangle face
for(i=1;i>=0;i--) {
kcos = ptx[i]*ptri->n; ksin = pty[i]*ptri->n;
k = (ptz[i]-ptri->pt[0]+pmode->center)*ptri->n;
a = sqr(ksin)+sqr(kcos); b = ksin*k; c = sqr(k)-sqr(kcos); d = b*b-a*c;
if (d>=0) {
d = sqrt_tpl(d); tsin.set(-b-d,a);
for(j=0;j<2;j++,tsin.x+=d*2)
if (isneg(fabs_tpl(tsin.x*2-tsin.y)-tsin.y) & // tsin in (0..1)
isneg((ksin*tsin.x+k*tsin.y)*kcos)) // tcos in (0..1)
{
tcos.set(sqrt_tpl(sqr(tsin.y)-sqr(tsin.x)),tsin.y);
pt = ptx[i]*tcos.x + pty[i]*tsin.x + (ptz[i]+pmode->center)*tsin.y;
bContact = // point is inside itri
isneg((pt-ptri->pt[0]*tsin.y ^ ptri->pt[1]-ptri->pt[0])*ptri->n) &
isneg((pt-ptri->pt[1]*tsin.y ^ ptri->pt[2]-ptri->pt[1])*ptri->n) &
isneg((pt-ptri->pt[2]*tsin.y ^ ptri->pt[0]-ptri->pt[2])*ptri->n);
bBest = bContact & isneg(tsin-tmin);
UPDATE_IDBEST(tmin,i);
}
}
if ((pray->origin-pmode->center).len2()<sqr(pmode->minPtDist))
break;
}
if (idbest>=0) {
i = idbest & 1;
pcontact->t = tmin.val();
pcontact->taux = sqrt_tpl(1-sqr(pcontact->t));
pcontact->pt = ptz[i] + ptx[i]*pcontact->taux + pty[i]*pcontact->t + pmode->center;
pcontact->n = -ptri->n;
pcontact->iFeature[0] = 0x80 | i;
pcontact->iFeature[1] = 0x40;
return 1;
}
// ray - triangle edge
pt = pray->origin-pmode->center^pray->dir; ptz0 = rotax*(pt*rotax); ptx0 = pt-ptz0; pty0 = rotax^ptx0;
for(i=0;i<3;i++) if ((0xA0 | (0xA0|i)<<8)!=imask) {
pt1 = ptri->pt[i]-pmode->center; edge1 = ptri->pt[inc_mod3[i]]-ptri->pt[i];
pt = pt1^edge1; ptz1 = rotax*(pt*rotax); ptx1 = pt-ptz1; pty1 = rotax^ptx1;
kcos = edge1*ptx0+pray->dir*ptx1; ksin = edge1*pty0-pray->dir*pty1; k = edge1*ptz0+pray->dir*ptz1;
a = sqr(ksin)+sqr(kcos); b = ksin*k; c = sqr(k)-sqr(kcos); d = b*b-a*c;
if (d>=0) {
d = sqrt_tpl(d); tsin.set(-b-d,a);
for(j=0;j<2;j++,tsin.x+=d*2)
if (isneg(fabs_tpl(tsin.x*2-tsin.y)-tsin.y) & // tsin in (0..1)
isneg((ksin*tsin.x+k*tsin.y)*kcos)) // tcos in (0..1)
{
tcos.set(sqrt_tpl(sqr(tsin.y)-sqr(tsin.x)),tsin.y);
pt0_rot = ptx[0]*tcos.x + pty[0]*tsin.x + ptz[0]*tsin.y;
pt1_rot = ptx[1]*tcos.x + pty[1]*tsin.x + ptz[1]*tsin.y;
edge0_rot = pt1_rot-pt0_rot;
n = edge0_rot^edge1; pt = pt1*tsin.y-pt0_rot;
t0.set((pt^edge1)*n, n.len2());
t1.set((pt^edge0_rot)*n, t0.y*tsin.y);
bContact = isneg(fabs_tpl(t0.x*2-t0.y)-t0.y) & isneg(fabs_tpl(t1.x*2-t1.y)-t1.y);
bBest = bContact & isneg(tsin-tmin);
UPDATE_IDBEST(tmin,i | 0x80);
}
}
}
if (idbest<0)
return 0;
i = idbest & 3;
pcontact->t = tmin.val();
pcontact->taux = sqrt_tpl(1-sqr(pcontact->t));
pt0_rot = ptx[0]*pcontact->taux + pty[0]*pcontact->t + ptz[0] + pmode->center;
pt1_rot = ptx[1]*pcontact->taux + pty[1]*pcontact->t + ptz[1] + pmode->center;
edge0_rot = pt1_rot-pt0_rot;
edge1 = ptri->pt[inc_mod3[i]]-ptri->pt[i];
pt = ptri->pt[i]-pt0_rot; n = edge0_rot ^ edge1;
t0.set((pt^edge1)*n, n.len2());
pcontact->pt = pt0_rot + edge0_rot*t0.val();
pcontact->n = n*sgnnz((ptri->n^edge1)*n);
pcontact->iFeature[0] = 0xA0;
pcontact->iFeature[1] = 0xA0 | i;
return 1;
}
int tri_ray_rot_unprojection(unprojection_mode *pmode, const triangle *ptri,int iFeature1, const ray *pray,int iFeature2,
contact *pcontact, geom_contact_area *parea)
{
(const_cast<unprojection_mode*>(pmode))->dir.Flip();
int res = ray_tri_rot_unprojection(pmode,pray,iFeature2,ptri,iFeature1,pcontact,parea);
if (res) {
pcontact->pt = pcontact->pt.rotated(pmode->center,pmode->dir, pcontact->taux,-pcontact->t);
pcontact->n = pcontact->n.rotated(pmode->dir, pcontact->taux,-pcontact->t).Flip();
int iFeature = pcontact->iFeature[0]; pcontact->iFeature[0]=pcontact->iFeature[1]; pcontact->iFeature[1]=iFeature;
}
(const_cast<unprojection_mode*>(pmode))->dir.Flip();
return res;
}
int ray_cyl_rot_unprojection(unprojection_mode *pmode, const ray *pray,int iFeature1, const cylinder *pcyl,int iFeature2,
contact *pcontact, geom_contact_area *parea)
{
vectorr center,ccap,v,vx,vy,vz,l,lx,ly,lz,vsin,vcos,pt,ptz[2],ptx[2],pty[2], rotax=pmode->dir, axis=pcyl->axis;
real a,b,c,d,k,ksin,kcos, hh=pcyl->hh, r2=sqr(pcyl->r), len2=pray->dir.len2(), roots[4];
quotient tmax(0,1),tsin,tcos,t;
int i,j,icap,idbest=-1,bContact,bBest;
polynomial_tpl<real,4> pn;
center = pcyl->center-pmode->center;
pt = pray->origin-pmode->center;
ptz[0] = rotax*(pt*rotax); ptx[0] = pt-ptz[0]; pty[0] = rotax^ptx[0];
pt += pray->dir;
ptz[1] = rotax*(pt*rotax); ptx[1] = pt-ptz[1]; pty[1] = rotax^ptx[1];
for(i=1; i>=0; i--) {
// ray end - cylinder cap
kcos = ptx[i]*axis; ksin = pty[i]*axis;
for(icap=-1; icap<=1; icap+=2) {
k = (ptz[i]-center-axis*(hh*icap))*axis;
a = sqr(ksin)+sqr(kcos); b = ksin*k; c = sqr(k)-sqr(kcos); d = b*b-a*c;
if (d>=0) {
d = sqrt_tpl(d); tsin.set(-b-d,a);
for(j=0;j<2;j++,tsin.x+=d*2)
if (isneg(fabs_tpl(tsin.x*2-tsin.y)-tsin.y) & // tsin in (0..1)
isneg((ksin*tsin.x+k*tsin.y)*kcos)) // tcos in (0..1) = remove phantom roots
{
tcos.set(sqrt_tpl(sqr(tsin.y)-sqr(tsin.x)),tsin.y);
pt = ptx[i]*tcos.x + pty[i]*tsin.x + ptz[i]*tsin.y;
bContact = isneg((pt-(center+axis*(hh*icap))*tsin.y).len2() - r2*sqr(tsin.y));
bBest = bContact & isneg(tmax-tsin);
UPDATE_IDBEST(tmax,icap+1|i);
}
}
}
// ray end - cylinder side
v = ptz[i]-center ^ axis;
vcos = ptx[i]^axis; vsin = pty[i]^axis;
pn = psqr(P2(sqr(vsin)-sqr(vcos)) + P1((v*vsin)*2) + sqr(v)+sqr(vcos)-r2) - psqr(P1(vcos*vsin)+v*vcos)*((real)1-P2(1))*4;
if (pn.nroots(0,1)) for(j=pn.findroots(0,1,roots)-1;j>=0;j--) {
tsin.set(roots[j],1);
pt = ptz[i]+ptx[i]*sqrt_tpl(1-sqr(tsin.x))+pty[i]*tsin.x-center;
bContact = isneg(fabs_tpl(pt*axis)-hh) & inrange((pt^axis).len2(), r2*sqr((real)0.99),r2*sqr((real)1.01));
bBest = isneg(tmax-tsin) & bContact;
UPDATE_IDBEST(tmax,0x10|i);
}
if ((pray->origin-pmode->center).len2()<sqr(pmode->minPtDist))
break;
}
// ray - cylinder side
lz = rotax*(pray->dir*rotax); lx = pray->dir-lz; ly = rotax^lx;
v = pray->origin-pmode->center^pray->dir;
vz = rotax*(v*rotax); vx = v-vz; vy = rotax^vx;
v = axis^center;
kcos = axis*vx-v*lx; ksin = axis*vy-v*ly; k = axis*vz-v*lz;
vcos = lx^axis; vsin = ly^axis; v = lz^axis;
pn = psqr(P2(sqr(ksin)-sqr(kcos)-r2*(sqr(vsin)-sqr(vcos)))+P1(((ksin*k)-r2*(vsin*v))*2)+sqr(kcos)+sqr(k)-r2*(sqr(vcos)+sqr(v))) -
psqr(P1((kcos*ksin-r2*(vcos*vsin))*2)+(kcos*k-r2*(vcos*v))*2);
if (pn.nroots(0,1)) for(j=pn.findroots(0,1,roots)-1;j>=0;j--) {
tsin.set(roots[j],1); tcos.x = sqrt_tpl(1-sqr(tsin.x));
pt = ptz[0] + ptx[0]*tcos.x + pty[0]*tsin.x - center;
l = lz + lx*tcos.x + ly*tsin.x; v = l^axis; k = v.len2();
bContact = inrange(sqr(pt*v), r2*k*sqr((real)0.99),r2*k*sqr((real)1.01)); // remove phantom roots
t.set((-pt^axis)*v, k);
(pt*=t.y) += l*t.x;
bContact &= inrange(sqr(t.x), (real)0,len2*sqr(t.y));
bContact &= isneg(fabs_tpl(pt*axis)-hh*t.y);
bBest = isneg(tmax-tsin) & bContact;
UPDATE_IDBEST(tmax,0x20);
}
// ray - cylinder cap
for(icap=-1; icap<=1; icap+=2) {
ccap = center+axis*(hh*icap);
vcos = (axis^vx)-(axis^(ccap^lx)); vsin = (axis^vy)-(axis^(ccap^ly)); v = (axis^vz)-(axis^(ccap^lz));
kcos = lx*axis; ksin = ly*axis; k = lz*axis;
pn = psqr(P2(sqr(vsin)-sqr(vcos)-r2*(sqr(ksin)-sqr(kcos)))+P1(((vsin*v)-r2*(ksin*k))*2)+sqr(vcos)+sqr(v)-r2*(sqr(kcos)+sqr(k))) -
psqr(P1((vcos*vsin-r2*(kcos*ksin))*2)+(vcos*v-r2*(kcos*k))*2);
if (pn.nroots(0,1)) for(j=pn.findroots(0,1,roots)-1;j>=0;j--) {
tsin.set(roots[j],1); tcos.x = sqrt_tpl(1-sqr(tsin.x));
pt = ptz[0] + ptx[0]*tcos.x + pty[0]*tsin.x;
l = lz + lx*tcos.x + ly*tsin.x;
t.set((ccap-pt)*axis, l*axis);
bContact = inrange(((pt-ccap)*t.y+l*t.x).len2(), r2*sqr(t.y*(real)0.99),r2*sqr(t.y*(real)1.01)); // remove phantom roots
bContact &= inrange(t.x, (real)0,t.y);
bBest = isneg(tmax-tsin) & bContact;
UPDATE_IDBEST(tmax,0x40|icap+1>>1);
}
}
if (idbest<0)
return 0;
switch (idbest & 0xF0) {
case 0x00: // ray end - cyl cap
i = idbest & 1; icap = (idbest&2)-1;
pcontact->t = tmax.val();
pcontact->taux = sqrt_tpl(1-sqr(pcontact->t));
pcontact->pt = ptz[i] + ptx[i]*pcontact->taux + pty[i]*pcontact->t + pmode->center;
pcontact->n = axis*-icap;
pcontact->iFeature[0] = 0x80 | i;
pcontact->iFeature[1] = 0x41 + (icap+1>>1);
break;
case 0x10: // ray end - cyl side
i = idbest & 1;
pcontact->t = tmax.x;
pcontact->taux = sqrt_tpl(1-sqr(pcontact->t));
pcontact->pt = ptz[i] + ptx[i]*pcontact->taux + pty[i]*pcontact->t + pmode->center;
pcontact->n = pcyl->center-pcontact->pt;
(pcontact->n -= pcyl->axis*(pcyl->axis*pcontact->n)).normalize();
pcontact->iFeature[0] = 0x80 | i;
pcontact->iFeature[1] = 0x40;
break;
case 0x20: // ray - cyl side
pcontact->t = tmax.x;
pcontact->taux = sqrt_tpl(1-sqr(pcontact->t));
pt = ptz[0] + ptx[0]*pcontact->taux + pty[0]*pcontact->t;
l = lz + lx*pcontact->taux + ly*pcontact->t;
t.set((pt^axis)*(l^axis),(l^axis).len2());
pcontact->pt = pt+l*t.val()+pmode->center;
pcontact->n = (l^axis).normalized();
pcontact->n *= sgnnz(pcontact->n*(pcyl->center-pcontact->pt));
pcontact->iFeature[0] = 0x20;
pcontact->iFeature[1] = 0x40;
break;
case 0x40: // ray - cyl cap
icap = ((idbest&1)<<1)-1;
pcontact->t = tmax.x;
pcontact->taux = sqrt_tpl(1-sqr(pcontact->t));
pt = ptz[0] + ptx[0]*pcontact->taux + pty[0]*pcontact->t;
l = lz + lx*pcontact->taux + ly*pcontact->t;
ccap = center+axis*(hh*icap);
t.set((ccap-pt)*axis,l*axis);
pcontact->pt = pt+l*t.val();
pcontact->n = pcontact->pt-ccap; pcontact->pt += pmode->center;
pcontact->n = ((axis^pcontact->n)^l).normalized();
pcontact->n *= sgnnz(pcontact->n*(pcyl->center-pcontact->pt));
pcontact->iFeature[0] = 0x20;
pcontact->iFeature[1] = 0x20|icap+1>>1;
}
return 1;
}
int cyl_ray_rot_unprojection(unprojection_mode *pmode, const cylinder *pcyl,int iFeature1, const ray *pray,int iFeature2,
contact *pcontact, geom_contact_area *parea)
{
(const_cast<unprojection_mode*>(pmode))->dir.Flip();
int res = ray_cyl_rot_unprojection(pmode,pray,iFeature2,pcyl,iFeature1,pcontact,parea);
if (res) {
pcontact->pt = pcontact->pt.rotated(pmode->center,pmode->dir, pcontact->taux,-pcontact->t);
pcontact->n = pcontact->n.rotated(pmode->dir, pcontact->taux,-pcontact->t).Flip();
int iFeature = pcontact->iFeature[0]; pcontact->iFeature[0]=pcontact->iFeature[1]; pcontact->iFeature[1]=iFeature;
}
(const_cast<unprojection_mode*>(pmode))->dir.Flip();
return res;
}
int ray_box_rot_unprojection(unprojection_mode *pmode, const ray *pray,int iFeature1, const box *pbox,int iFeature2,
contact *pcontact, geom_contact_area *parea)
{
int i,j,ifeat,idir,ix,iy,bContact,bBest,idbest=-1;
vectorr pt,ptz[2],ptx[2],pty[2],ptz0,ptx0,pty0,pt1,pt0_rot,pt1_rot,edge0_rot,ptz1,ptx1,pty1,origin,dir,center,rotax,n,size;
quotient tsin,tcos,tmax(0,1),t0,t1;
real kcos,ksin,k,a,b,c,d;
origin = pbox->Basis*(pray->origin-pbox->center);
dir = pbox->Basis*pray->dir;
center = pbox->Basis*(pmode->center-pbox->center);
rotax = pbox->Basis*pmode->dir;
size = pbox->size;
pt = origin-center; ptz[0] = rotax*(pt*rotax); ptx[0] = pt-ptz[0]; pty[0] = rotax^ptx[0];
pt += dir; ptz[1] = rotax*(pt*rotax); ptx[1] = pt-ptz[1]; pty[1] = rotax^ptx[1];
// ray end - box face
for(i=1;i>=0;i--) {
for(ifeat=0;ifeat<6;ifeat++) {
idir = ifeat>>1; ix = inc_mod3[idir]; iy = dec_mod3[idir];
kcos = ptx[i][idir]; ksin = pty[i][idir];
k = ptz[i][idir]-size[idir]*((ifeat&1)*2-1)+center[idir];
a = sqr(ksin)+sqr(kcos); b = ksin*k; c = sqr(k)-sqr(kcos); d = b*b-a*c;
if (d>=0) {
d = sqrt_tpl(d); tsin.set(-b-d,a);
for(j=0;j<2;j++,tsin.x+=d*2)
if (isneg(fabs_tpl(tsin.x*2-tsin.y)-tsin.y) & // tsin in (0..1)
isneg((ksin*tsin.x+k*tsin.y)*kcos)) // tcos in (0..1) = remove phantom roots
{
tcos.set(sqrt_tpl(sqr(tsin.y)-sqr(tsin.x)),tsin.y);
pt = ptx[i]*tcos.x + pty[i]*tsin.x + (ptz[i]+pmode->center)*tsin.y;
bContact = // point is inside the face
isneg(fabs_tpl(pt[ix])-size[ix]*tsin.y) & isneg(fabs_tpl(pt[iy])-size[iy]*tsin.y);
bBest = bContact & isneg(tmax-tsin);
UPDATE_IDBEST(tmax,i|ifeat<<1);
}
}
}
if ((pray->origin-pmode->center).len2()<sqr(pmode->minPtDist))
break;
}
// ray - box edge
pt = origin-center^dir; ptz0 = rotax*(pt*rotax); ptx0 = pt-ptz0; pty0 = rotax^ptx0;
for(ifeat=0;ifeat<12;ifeat++) {
idir = ifeat>>2; ix = inc_mod3[idir]; iy = dec_mod3[idir];
pt1[idir]=0; pt1[ix]=size[ix]*((ifeat&1)*2-1); pt1[iy]=size[iy]*((ifeat&2)-1);
pt1 = pt1-center;
pt = cross_with_ort(pt1,idir); ptz1 = rotax*(pt*rotax); ptx1 = pt-ptz1; pty1 = rotax^ptx1;
kcos = ptx0[idir]+dir*ptx1; ksin = pty0[idir]-dir*pty1; k = ptz0[idir]+dir*ptz1;
a = sqr(ksin)+sqr(kcos); b = ksin*k; c = sqr(k)-sqr(kcos); d = b*b-a*c;
if (d>=0) {
d = sqrt_tpl(d); tsin.set(-b-d,a);
for(j=0;j<2;j++,tsin.x+=d*2)
if (isneg(fabs_tpl(tsin.x*2-tsin.y)-tsin.y) & // tsin in (0..1)
isneg((ksin*tsin.x+k*tsin.y)*kcos)) // tcos in (0..1)
{
tcos.set(sqrt_tpl(sqr(tsin.y)-sqr(tsin.x)),tsin.y);
pt0_rot = ptx[0]*tcos.x + pty[0]*tsin.x + ptz[0]*tsin.y;
pt1_rot = ptx[1]*tcos.x + pty[1]*tsin.x + ptz[1]*tsin.y;
edge0_rot = pt1_rot-pt0_rot;
n = cross_with_ort(edge0_rot,idir); pt = pt1*tsin.y-pt0_rot;
t0.set(cross_with_ort(pt,idir)*n, n.len2());
t1.set((pt^edge0_rot)*n, t0.y*tsin.y);
bContact = inrange(t0.x, (real)0,t0.y) & isneg(fabs_tpl(t1.x)-fabs_tpl(t1.y)*size[idir]);
bBest = bContact & isneg(tmax-tsin);
UPDATE_IDBEST(tmax,ifeat | 0x80);
}
}
}
if (idbest<0)
return 0;
if ((idbest & 0x80)==0) {
i = idbest & 1; ifeat = idbest>>1; idir = ifeat>>1;
pcontact->t = tmax.val();
pcontact->taux = sqrt_tpl(1-sqr(pcontact->t));
pcontact->pt = (ptz[i] + ptx[i]*pcontact->taux + pty[i]*pcontact->t + center)*pbox->Basis + pbox->center;
pcontact->n.zero()[idir]=1-(ifeat&1)*2; pcontact->n = pcontact->n*pbox->Basis;
pcontact->iFeature[0] = 0x80 | i;
pcontact->iFeature[1] = 0x40 | ifeat;
} else {
ifeat = idbest&0x7F; idir = ifeat>>2; ix = inc_mod3[idir]; iy = dec_mod3[idir];
pcontact->t = tmax.val();
pcontact->taux = sqrt_tpl(1-sqr(pcontact->t));
pt0_rot = ptx[0]*pcontact->taux + pty[0]*pcontact->t + ptz[0] + center;
pt1_rot = ptx[1]*pcontact->taux + pty[1]*pcontact->t + ptz[1] + center;
edge0_rot = pt1_rot-pt0_rot;
pt[idir]=0; pt[ix]=size[ix]*((ifeat&1)*2-1); pt[iy]=size[iy]*((ifeat&2)-1);
n = cross_with_ort(edge0_rot,idir);
t0.set(cross_with_ort(pt-pt0_rot,idir)*n, n.len2());
pt = pt0_rot + edge0_rot*t0.val();
pcontact->n = (n*-sgnnz(n*pt))*pbox->Basis;
pcontact->pt = pt*pbox->Basis+pbox->center;
pcontact->iFeature[0] = 0xA0;
pcontact->iFeature[1] = 0x20 | ifeat;
}
return 1;
}
int box_ray_rot_unprojection(unprojection_mode *pmode, const box *pbox,int iFeature1, const ray *pray,int iFeature2,
contact *pcontact, geom_contact_area *parea)
{
(const_cast<unprojection_mode*>(pmode))->dir.Flip();
int res = ray_box_rot_unprojection(pmode,pray,iFeature2,pbox,iFeature1,pcontact,parea);
if (res) {
pcontact->pt = pcontact->pt.rotated(pmode->center,pmode->dir, pcontact->taux,-pcontact->t);
pcontact->n = pcontact->n.rotated(pmode->dir, pcontact->taux,-pcontact->t).Flip();
int iFeature = pcontact->iFeature[0]; pcontact->iFeature[0]=pcontact->iFeature[1]; pcontact->iFeature[1]=iFeature;
}
(const_cast<unprojection_mode*>(pmode))->dir.Flip();
return res;
}

View File

@@ -0,0 +1,114 @@
#include "stdafx.h"
#include "utils.h"
#include "primitives.h"
#include "bvtree.h"
#include "geometry.h"
#include "singleboxtree.h"
float CSingleBoxTree::Build(CGeometry *pGeom)
{
m_pGeom = pGeom;
return m_Box.size.volume()*8;
}
void CSingleBoxTree::SetBox(box *pbox)
{
m_Box.Basis = pbox->Basis;
m_Box.bOriented = m_Box.Basis.IsIdentity()^1;
m_Box.center = pbox->center;
m_Box.size = pbox->size;
}
void CSingleBoxTree::GetNodeBV(BV *&pBV,int iNode)
{
pBV = g_BBoxBuf + g_BBoxBufPos++;
pBV->type = box::type;
pBV->iNode = 0;
((BBox*)pBV)->abox.Basis = m_Box.Basis;
((BBox*)pBV)->abox.bOriented = m_Box.bOriented;
((BBox*)pBV)->abox.center = m_Box.center;
((BBox*)pBV)->abox.size = m_Box.size;
}
void CSingleBoxTree::GetNodeBV(BV *&pBV, const vectorf &sweepdir,float sweepstep, int iNode)
{
pBV = g_BBoxBuf + g_BBoxBufPos++;
pBV->type = box::type;
pBV->iNode = 0;
box boxstatic;
boxstatic.Basis = m_Box.Basis;
boxstatic.bOriented = m_Box.bOriented;
boxstatic.center = m_Box.center;
boxstatic.size = m_Box.size;
ExtrudeBox(&boxstatic, sweepdir,sweepstep, &((BBox*)pBV)->abox);
}
void CSingleBoxTree::GetNodeBV(const matrix3x3f &Rw,const vectorf &offsw,float scalew, BV *&pBV, int iNode)
{
pBV = g_BBoxBuf + g_BBoxBufPos++;
pBV->type = box::type;
pBV->iNode = 0;
((BBox*)pBV)->abox.Basis = m_Box.Basis*Rw.T();
((BBox*)pBV)->abox.bOriented = 1;
((BBox*)pBV)->abox.center = Rw*m_Box.center*scalew + offsw;
((BBox*)pBV)->abox.size = m_Box.size*scalew;
}
void CSingleBoxTree::GetNodeBV(const matrix3x3f &Rw,const vectorf &offsw,float scalew, BV *&pBV,
const vectorf &sweepdir,float sweepstep, int iNode)
{
pBV = g_BBoxBuf + g_BBoxBufPos++;
pBV->type = box::type;
pBV->iNode = 0;
box boxstatic;
boxstatic.Basis = m_Box.Basis*Rw.T();
boxstatic.bOriented = 1;
boxstatic.center = Rw*m_Box.center*scalew + offsw;
boxstatic.size = m_Box.size*scalew;
ExtrudeBox(&boxstatic, sweepdir,sweepstep, &((BBox*)pBV)->abox);
}
int CSingleBoxTree::GetNodeContents(int iNode, BV *pBVCollider,int bColliderUsed,int bColliderLocal,
geometry_under_test *pGTest,geometry_under_test *pGTestOp)
{
return m_pGeom->GetPrimitiveList(0,m_nPrims, pBVCollider->type,*pBVCollider,bColliderLocal, pGTest,pGTestOp, pGTest->primbuf,pGTest->idbuf);
}
int CSingleBoxTree::PrepareForIntersectionTest(geometry_under_test *pGTest)
{
pGTest->pUsedNodesMap = &pGTest->nUsedNodes;
pGTest->nUsedNodes = 0;
return 1;
}
void CSingleBoxTree::MarkUsedTriangle(int itri, geometry_under_test *pGTest)
{
pGTest->nUsedNodes = 1;
}
void CSingleBoxTree::GetBBox(box *pbox)
{
pbox->Basis = m_Box.Basis;
pbox->bOriented = m_Box.bOriented;
pbox->center = m_Box.center;
pbox->size = m_Box.size;
}
void CSingleBoxTree::GetMemoryStatistics(ICrySizer *pSizer)
{
SIZER_COMPONENT_NAME(pSizer, "SingleBox trees");
pSizer->AddObject(this, sizeof(CSingleBoxTree));
}
void CSingleBoxTree::Save(CMemStream &stm)
{
stm.Write(m_Box);
stm.Write(m_nPrims);
}
void CSingleBoxTree::Load(CMemStream &stm, CGeometry *pGeom)
{
m_pGeom = pGeom;
stm.Read(m_Box);
stm.Read(m_nPrims);
}

View File

@@ -0,0 +1,31 @@
#ifndef singleboxtree_h
#define singleboxtree_h
class CSingleBoxTree : public CBVTree {
public:
CSingleBoxTree() { m_nPrims = 1; }
virtual int GetType() { return BVT_SINGLEBOX; }
virtual float Build(CGeometry *pGeom);
void SetBox(box *pbox);
virtual int PrepareForIntersectionTest(geometry_under_test *pGTest);
virtual void GetBBox(box *pbox);
virtual int MaxPrimsInNode() { return m_nPrims; }
virtual void GetNodeBV(BV *&pBV, int iNode=0);
virtual void GetNodeBV(BV *&pBV, const vectorf &sweepdir,float sweepstep, int iNode=0);
virtual void GetNodeBV(const matrix3x3f &Rw,const vectorf &offsw,float scalew, BV *&pBV, int iNode=0);
virtual void GetNodeBV(const matrix3x3f &Rw,const vectorf &offsw,float scalew, BV *&pBV, const vectorf &sweepdir,float sweepstep, int iNode=0);
virtual int GetNodeContents(int iNode, BV *pBVCollider,int bColliderUsed,int bColliderLocal,
geometry_under_test *pGTest,geometry_under_test *pGTestOp);
virtual int GetNodeContentsIdx(int iNode, int &iStartPrim) { iStartPrim=0; return m_nPrims; }
virtual void MarkUsedTriangle(int itri, geometry_under_test *pGTest);
virtual void GetMemoryStatistics(ICrySizer *pSizer);
virtual void Save(CMemStream &stm);
virtual void Load(CMemStream &stm, CGeometry *pGeom);
CGeometry *m_pGeom;
box m_Box;
int m_nPrims;
};
#endif

982
CryPhysics/softentity.cpp Normal file
View File

@@ -0,0 +1,982 @@
//////////////////////////////////////////////////////////////////////
//
// Soft Entity
//
// File: softentity.cpp
// Description : CSoftEntity class implementation
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "bvtree.h"
#include "geometry.h"
#include "overlapchecks.h"
#include "intersectionchecks.h"
#include "raybv.h"
#include "raygeom.h"
#include "singleboxtree.h"
#include "trimesh.h"
#include "rigidbody.h"
#include "physicalplaceholder.h"
#include "physicalentity.h"
#include "geoman.h"
#include "physicalworld.h"
#include "softentity.h"
CSoftEntity::CSoftEntity(CPhysicalWorld *pworld) : CPhysicalEntity(pworld)
{
m_vtx=0; m_edges=0; m_pVtxEdges=0;
m_nVtx=m_nEdges=0;
m_maxAllowedStep = 0.1f;
m_ks = 200.0f;
m_thickness = 0.04f;
m_maxSafeStep = 0.2f;
m_kdRatio = 0.9f;
m_airResistance = 0;//10.0f;
m_wind.zero();
m_waterDensity = 0;
m_waterPlane.n.Set(0,0,1);
m_waterPlane.origin.Set(0,0,0);
m_waterFlow.zero();
m_waterResistance = 0;
m_waterDamping = 1.5f;
m_gravity.Set(0,0,-9.8f);
m_damping = 0;
m_Emin = sqr(0.01f);
m_iSimClass = 4;
m_accuracy = 0.01f;
m_nMaxIters = 1024;
m_prevTimeInterval = 0;
m_bAwake = 1;
m_nSlowFrames = 0;
m_friction = 0;
m_impulseScale = 0.05f;
m_explosionScale = 0.001f;
m_qrot0.SetIdentity();
m_collImpulseScale = 1.0f;
m_bMeshUpdated = 0;
m_collTypes = /*ent_terrain |*/ ent_static|ent_sleeping_rigid|ent_rigid|ent_living;
m_maxCollImpulse = 3000;
}
CSoftEntity::~CSoftEntity()
{
AlertNeighbourhoodND();
}
void CSoftEntity::AlertNeighbourhoodND()
{
if (m_vtx) { delete[] m_vtx; m_vtx=0; }
if (m_edges) { delete[] m_edges; m_edges=0; }
if (m_pVtxEdges) { delete[] m_pVtxEdges; m_pVtxEdges=0; }
m_nVtx=m_nEdges = 0;
}
int CSoftEntity::AddGeometry(phys_geometry *pgeom, pe_geomparams* params, int id)
{
if (!pgeom || pgeom->pGeom->GetType()!=GEOM_TRIMESH || m_nParts>0)
return -1;
int res = CPhysicalEntity::AddGeometry(pgeom,params,id);
int i,j,i0,i1,bDegen,iedge,itri,itri0,ivtx,itrinew,nVtxEdges,(*pInfo)[3];
float rvtxmass,vtxvol,len[3];
CTriMesh *pMesh = (CTriMesh*)pgeom->pGeom;
rvtxmass = pMesh->m_nVertices/params->mass;
vtxvol = 1.0f/(rvtxmass*params->density);
m_density = params->density;
m_vtx = new se_vertex[m_nVtx = pMesh->m_nVertices];
for(i=0;i<m_nVtx;i++) {
m_vtx[i].posorg = pMesh->m_pVertices[i];
m_vtx[i].pos = m_qrot0*(params->q*pMesh->m_pVertices[i]*params->scale+params->pos);
m_vtx[i].massinv = rvtxmass; m_vtx[i].volume = vtxvol;
m_vtx[i].vel.zero(); m_vtx[i].bSeparating=m_vtx[i].iSorted=m_vtx[i].bAttached = 0;
m_vtx[i].pContactEnt = 0; m_vtx[i].iContactNode = 0; m_vtx[i].ncontact.zero(); m_vtx[i].n.zero();
}
m_offs0 = m_vtx[0].pos;
for(i=1;i<m_nVtx;i++) m_vtx[i].pos -= m_vtx[0].pos;
m_vtx[0].pos.zero();
memset(pInfo=new int[pMesh->m_nTris][3],-1,pMesh->m_nTris*sizeof(pInfo[0]));
// count the number of edges - for each tri, mark each edge, unless buddy already did it
for(i=m_nEdges=0;i<pMesh->m_nTris;i++) {
for(j=bDegen=0;j<3;j++) {
len[j] = (pMesh->m_pVertices[pMesh->m_pIndices[i*3+j]]-pMesh->m_pVertices[pMesh->m_pIndices[i*3+inc_mod3[j]]]).len2();
bDegen |= iszero(len[j]);
}
iedge = idxmax3(len); j = iedge&-bDegen;
do {
if (pInfo[i][j]<0 && !(m_flags&se_skip_longest_edges && j==iedge && !bDegen)) {
if (pMesh->m_pTopology[i].ibuddy[j]>=0)
pInfo[ pMesh->m_pTopology[i].ibuddy[j] ][ pMesh->GetEdgeByBuddy(pMesh->m_pTopology[i].ibuddy[j],i) ] = m_nEdges;
pInfo[i][j] = m_nEdges++;
}
} while(++j<3 && !bDegen);
}
m_edges = new se_edge[m_nEdges];
m_pVtxEdges = new int[m_nEdges*2];
for(i=0;i<pMesh->m_nTris;i++) for(j=0;j<3;j++) if ((iedge=pInfo[i][j])>=0) {
i0 = m_edges[iedge].ivtx[0] = pMesh->m_pIndices[i*3+j];
i1 = m_edges[iedge].ivtx[1] = pMesh->m_pIndices[i*3+inc_mod3[j]];
m_edges[iedge].len0 = (pMesh->m_pVertices[i0]-pMesh->m_pVertices[i1]).len()*params->scale;
m_edges[pInfo[i][j]].kd = m_vtx[i0].massinv+m_vtx[i1].massinv>0 ?
sqrt_tpl(m_ks/(m_vtx[i0].massinv+m_vtx[i1].massinv))*2.0f*m_kdRatio : 0;
}
// for each vertex, trace ccw fan around it and store in m_pVtxEdges
m_BBox[0].zero(); m_BBox[1].zero();
for(i=nVtxEdges=0; i<pMesh->m_nTris; i++)
for(j=0;j<3;j++) if (!m_vtx[ivtx=pMesh->m_pIndices[i*3+j]].iSorted) {
itri=i; iedge=j;
m_vtx[ivtx].iStartEdge = nVtxEdges; m_vtx[ivtx].bFullFan = 1;
do { // first, trace cw fan until we find an open edge (if any)
if ((itrinew = pMesh->m_pTopology[itri].ibuddy[iedge])<=0)
break;
iedge = inc_mod3[pMesh->GetEdgeByBuddy(itrinew,itri)];
} while((itri=itrinew)!=i);
itri0 = itri;
do { // now trace ccw fan
if (pInfo[itri][iedge]>=0)
m_pVtxEdges[nVtxEdges++] = pInfo[itri][iedge];
if ((itrinew = pMesh->m_pTopology[itri].ibuddy[dec_mod3[iedge]])<0) {
if (pInfo[itri][dec_mod3[iedge]]>=0)
m_pVtxEdges[nVtxEdges++] = pInfo[itri][dec_mod3[iedge]];
m_vtx[ivtx].bFullFan = 0; break;
}
iedge = pMesh->GetEdgeByBuddy(itrinew,itri);
} while ((itri=itrinew)!=itri0);
m_vtx[ivtx].iEndEdge = nVtxEdges-1;
m_vtx[ivtx].rnEdges = 1.0f/(nVtxEdges-m_vtx[ivtx].iStartEdge);
m_vtx[ivtx].iSorted = 1;
m_vtx[ivtx].surface_idx[0] = pMesh->m_pIds ? pMesh->m_pIds[i]:-1;
m_BBox[0].x=min(m_BBox[0].x,m_vtx[ivtx].pos.x); m_BBox[1].x=max(m_BBox[1].x,m_vtx[ivtx].pos.x);
m_BBox[0].y=min(m_BBox[0].y,m_vtx[ivtx].pos.y); m_BBox[1].y=max(m_BBox[1].y,m_vtx[ivtx].pos.y);
m_BBox[0].z=min(m_BBox[0].z,m_vtx[ivtx].pos.z); m_BBox[1].z=max(m_BBox[1].z,m_vtx[ivtx].pos.z);
}
delete[] pInfo;
m_coverage = m_flags&se_skip_longest_edges ? 0.5f: 1.0f/3;
m_BBox[0] += m_pos+m_offs0; m_BBox[1] += m_pos+m_offs0;
box bbox;
bbox.Basis.SetIdentity();
bbox.bOriented = 0;
bbox.center = (m_BBox[0]+m_BBox[1])*0.5f-m_pos-m_parts[0].pos;
bbox.size = (m_BBox[1]-m_BBox[0])*(0.5f/params->scale);
if (pMesh->m_pTree)
delete pMesh->m_pTree;
CSingleBoxTree *pTree = new CSingleBoxTree;
pTree->SetBox(&bbox);
pTree->Build(pMesh);
pTree->m_nPrims = pMesh->m_nTris;
pMesh->m_pTree = pTree;
m_flags |= pef_use_geom_callbacks;
m_bMeshUpdated = 0;
return res;
}
void CSoftEntity::RemoveGeometry(int id)
{
int i;
for(i=0;i<m_nParts && m_parts[i].id!=id;i++);
if (i==m_nParts) return;
if (m_vtx) { delete[] m_vtx; m_vtx=0; }
if (m_edges) { delete[] m_edges; m_edges=0; }
if (m_pVtxEdges) { delete[] m_pVtxEdges; m_pVtxEdges=0; }
m_nVtx=m_nEdges = 0;
CPhysicalEntity::RemoveGeometry(id);
}
int CSoftEntity::SetParams(pe_params *_params)
{
int res = CPhysicalEntity::SetParams(_params);
if (res) {
if (_params->type==pe_params_pos::type_id && !is_unused(((pe_params_pos*)_params)->q)) {
if (m_nVtx>0 && (m_qrot0|m_qrot)<0.998f) {
CTriMesh *pMesh = (CTriMesh*)m_parts[0].pPhysGeom->pGeom;
int i; quaternionf qrot = m_bMeshUpdated ? m_qrot*!m_qrot0 : m_qrot;
for(i=0;i<m_nVtx;i++) {
m_vtx[i].pos = qrot*(m_parts[0].q*pMesh->m_pVertices[i]*m_parts[0].scale+m_parts[0].pos);
if (m_vtx[i].bAttached==2 && m_vtx[i].pContactEnt) {
RigidBody *pbody = m_vtx[i].pContactEnt->GetRigidBody(m_vtx[i].iContactPart);
m_vtx[i].ptAttach = (m_vtx[i].pos+m_pos-pbody->pos)*pbody->q;
}
}
m_offs0 = m_vtx[0].pos;
for(i=1;i<m_nVtx;i++) m_vtx[i].pos -= m_vtx[0].pos;
m_vtx[0].pos.zero();
}
m_qrot0 = m_qrot; m_qrot.SetIdentity();
}
return res;
}
if (_params->type==pe_simulation_params::type_id) {
pe_simulation_params *params = (pe_simulation_params*)_params;
if (!is_unused(params->gravity)) m_gravity = params->gravity;
if (!is_unused(params->maxTimeStep)) m_maxAllowedStep = params->maxTimeStep;
if (!is_unused(params->minEnergy)) m_Emin = params->minEnergy;
if (!is_unused(params->damping)) m_damping = params->damping;
if (!is_unused(params->density) && params->density>=0 && m_nParts>0) {
for(int i=0;i<m_nVtx;i++) if (m_vtx[i].massinv>0)
m_vtx[i].volume = 1.0f/(m_vtx[i].massinv*params->density);
m_density = params->density;
}
if (!is_unused(params->mass) && params->mass>=0 && m_nParts>0) {
float rvtxmass = m_nVtx/params->mass;
for(int i=0;i<m_nVtx;i++) if (m_vtx[i].massinv>0)
m_vtx[i].massinv = rvtxmass;
m_parts[0].mass = params->mass;
}
if (!is_unused(params->iSimClass)) {
m_iSimClass = params->iSimClass;
m_pWorld->RepositionEntity(this,2);
}
return 1;
}
if (_params->type==pe_params_buoyancy::type_id) {
pe_params_buoyancy *params = (pe_params_buoyancy*)_params;
if (!is_unused(params->waterDensity)) {
if (m_waterDensity!=params->waterDensity)
m_bAwake = 1;
m_waterDensity = params->waterDensity;
}
if (!is_unused(params->waterDamping)) m_waterDamping = params->waterDamping;
if (!is_unused(params->waterPlane.n)) {
if ((m_waterPlane.n-params->waterPlane.n).len2()>0)
m_bAwake = 1;
m_waterPlane.n = params->waterPlane.n;
}
if (!is_unused(params->waterPlane.origin)) {
if ((m_waterPlane.origin-params->waterPlane.origin).len2()>0)
m_bAwake = 1;
m_waterPlane.origin = params->waterPlane.origin;
}
if (!is_unused(params->waterFlow)) {
if ((m_waterFlow-params->waterFlow).len2()>0)
m_bAwake = 1;
m_waterFlow = params->waterFlow;
}
if (!is_unused(params->waterResistance)) m_waterResistance = params->waterResistance;
return 1;
}
if (_params->type==pe_params_softbody::type_id) {
pe_params_softbody *params = (pe_params_softbody*)_params;
if (!is_unused(params->thickness)) m_thickness = params->thickness;
if (!is_unused(params->friction)) m_friction = params->friction;
if (!is_unused(params->ks)) m_ks = params->ks;
if (!is_unused(params->kdRatio)) m_kdRatio = params->kdRatio;
if (!is_unused(params->ks) || !is_unused(params->kdRatio)) {
for(int i=0;i<m_nEdges;i++) if (m_vtx[m_edges[i].ivtx[0]].massinv+m_vtx[m_edges[i].ivtx[1]].massinv>0)
m_edges[i].kd = sqrt_tpl(m_ks/(m_vtx[m_edges[i].ivtx[0]].massinv+m_vtx[m_edges[i].ivtx[1]].massinv))*2.0f*m_kdRatio;
}
if (!is_unused(params->airResistance)) m_airResistance = params->airResistance;
if (!is_unused(params->wind)) m_wind = params->wind;
if (!is_unused(params->accuracy)) m_accuracy = params->accuracy;
if (!is_unused(params->nMaxIters)) m_nMaxIters = params->nMaxIters;
if (!is_unused(params->maxSafeStep)) m_maxSafeStep = params->maxSafeStep;
if (!is_unused(params->impulseScale)) m_impulseScale = params->impulseScale;
if (!is_unused(params->explosionScale)) m_explosionScale = params->explosionScale;
if (!is_unused(params->collisionImpulseScale)) m_collImpulseScale = params->collisionImpulseScale;
if (!is_unused(params->maxCollisionImpulse)) m_maxCollImpulse = params->maxCollisionImpulse;
if (!is_unused(params->collTypes)) m_collTypes = params->collTypes;
return 1;
}
return CPhysicalEntity::SetParams(_params);
}
int CSoftEntity::GetParams(pe_params *_params)
{
if (_params->type==pe_simulation_params::type_id) {
pe_simulation_params *params = (pe_simulation_params*)_params;
params->gravity=params->gravityFreefall = m_gravity;
params->maxTimeStep = m_maxAllowedStep;
params->minEnergy = m_Emin;
params->damping=params->dampingFreefall = m_damping;
params->mass = m_parts[0].mass;
params->density = m_density;
params->iSimClass = m_iSimClass;
return 1;
}
if (_params->type==pe_params_buoyancy::type_id) {
pe_params_buoyancy *params = (pe_params_buoyancy*)_params;
params->waterDensity = m_waterDensity;
params->waterDamping = m_waterDamping;
params->waterPlane = m_waterPlane;
params->waterFlow = m_waterFlow;
params->waterResistance = m_waterResistance;
params->waterEmin = m_Emin;
return 1;
}
if (_params->type==pe_params_softbody::type_id) {
pe_params_softbody *params = (pe_params_softbody*)_params;
params->thickness = m_thickness;
params->friction = m_friction;
params->ks = m_ks;
params->kdRatio = m_kdRatio;
params->airResistance = m_airResistance;
params->wind = m_wind;
params->accuracy = m_accuracy;
params->nMaxIters = m_nMaxIters;
params->maxSafeStep = m_maxSafeStep;
params->impulseScale = m_impulseScale;
params->explosionScale = m_explosionScale;
params->collisionImpulseScale = m_collImpulseScale;
params->maxCollisionImpulse = m_maxCollImpulse;
params->collTypes = m_collTypes;
return 1;
}
return CPhysicalEntity::GetParams(_params);
}
int CSoftEntity::GetStatus(pe_status *_status)
{
int res;
if (res = CPhysicalEntity::GetStatus(_status)) {
if (_status->type==pe_status_caps::type_id) {
pe_status_caps *status = (pe_status_caps*)_status;
status->bCanAlterOrientation = 1;
}
return res;
}
if (_status->type==pe_status_softvtx::type_id) {
if (m_nVtx<=0)
return 0;
pe_status_softvtx *status = (pe_status_softvtx*)_status;
status->nVtx = m_nVtx;
status->pVtx = ((CTriMesh*)m_parts[0].pPhysGeomProxy->pGeom)->m_pVertices;
status->pNormals.data = &m_vtx[0].n;
status->pNormals.iStride = sizeof(m_vtx[0]);
return 1;
}
if (_status->type==pe_status_collisions::type_id) {
pe_status_collisions *status = (pe_status_collisions*)_status;
int i,j,n;
if (status->len<=0)
return 0;
for(i=n=0;i<m_nVtx;i++) if (!m_vtx[i].bAttached && m_vtx[i].pContactEnt) {
if (n==status->len) {
for(n=1,j=0; n<status->len; n++)
if ((status->pHistory[n].v[0]-status->pHistory[n].v[1]).len2() < (status->pHistory[j].v[0]-status->pHistory[j].v[1]).len2())
j = n;
if ((status->pHistory[j].v[0]-status->pHistory[j].v[1]).len2() > (m_vtx[i].vel-m_vtx[i].vcontact).len2())
continue;
} else j=n++;
status->pHistory[j].pt = m_vtx[i].pos;
status->pHistory[j].n = m_vtx[i].ncontact;
status->pHistory[j].v[0] = m_vtx[i].vel;
status->pHistory[j].v[1] = m_vtx[i].vcontact;
status->pHistory[j].mass[0] = m_parts[0].mass;
status->pHistory[j].mass[1] = m_vtx[i].pContactEnt->GetMassInv();
if (status->pHistory[j].mass[1]>0)
status->pHistory[j].mass[1] = 1.0f/status->pHistory[j].mass[1];
status->pHistory[j].age = 0;
status->pHistory[j].idCollider = m_pWorld->GetPhysicalEntityId(m_vtx[i].pContactEnt);
status->pHistory[j].partid[0] = 0;
status->pHistory[j].partid[1] = m_vtx[i].iContactPart;
status->pHistory[j].idmat[0] = m_vtx[i].surface_idx[0];
status->pHistory[j].idmat[1] = m_vtx[i].surface_idx[1];
}
return status->len = n;
}
return 0;
}
int CSoftEntity::Action(pe_action *_action)
{
if (_action->type==pe_action_impulse::type_id) {
pe_action_impulse *action = (pe_action_impulse*)_action;
ENTITY_VALIDATE("CSoftEntity:Action(action_impulse)",action);
if (m_nVtx>0 && !is_unused(action->point) && !is_unused(action->impulse)) {
CTriMesh *pMesh = (CTriMesh*)m_parts[0].pPhysGeom->pGeom;
vectorf pt=action->point-(m_pos+m_offs0), impulse=action->impulse*m_impulseScale;
int i,j,bBest;
if (!is_unused(action->ipart)) i = action->ipart;
else i = action->partid;
m_bAwake = 1;
if ((unsigned int)i < (unsigned int)pMesh->m_nTris) {
float rarea,k; int idx[3];
for(j=0;j<3;j++) idx[j] = pMesh->m_pIndices[i*3+j];
rarea = (m_vtx[idx[1]].pos-m_vtx[idx[0]].pos ^ m_vtx[idx[2]].pos-m_vtx[idx[0]].pos).len();
if (rarea>1E-4f) {
rarea = 1.0f/rarea;
for(j=0;j<3;j++) {
k = (m_vtx[idx[inc_mod3[j]]].pos-pt ^ m_vtx[idx[j]].pos-pt).len()*rarea;
m_vtx[idx[dec_mod3[j]]].vel += impulse*(m_vtx[idx[dec_mod3[j]]].massinv*k);
}
} else
m_vtx[idx[0]].vel += impulse*m_vtx[idx[0]].massinv;
} else {
for(i=1,j=0;i<m_nVtx;i++) {
bBest = -isneg((m_vtx[i].pos-pt).len2()-(m_vtx[j].pos-pt).len2());
j = i&bBest | j&~bBest;
}
m_vtx[j].vel += impulse*m_vtx[j].massinv;
}
}
return 1;
}
if (_action->type==pe_action_attach_points::type_id) {
pe_action_attach_points *action = (pe_action_attach_points*)_action;
CPhysicalEntity* pent = action->pEntity==WORLD_ENTITY ? &g_StaticPhysicalEntity :
action->pEntity ? ((CPhysicalPlaceholder*)action->pEntity)->GetEntity() : 0;
int ipart=0, bAttached=iszero((intptr_t)pent)^1;
if (bAttached && is_unused(action->points))
bAttached = 2;
float rvtxmass = pent ? 0 : m_nVtx/m_parts[0].mass;
if (!is_unused(action->partid)) {
for(ipart=0; ipart<pent->m_nParts && pent->m_parts[ipart].id!=action->partid; ipart++);
if (ipart>=pent->m_nParts)
return 0;
}
RigidBody *pbody;
if (bAttached)
pbody = pent->GetRigidBody(ipart);
for(int i=0;i<action->nPoints;i++) {
if (m_vtx[action->piVtx[i]].pContactEnt) m_vtx[action->piVtx[i]].pContactEnt->Release();
if (m_vtx[action->piVtx[i]].pContactEnt = pent)
pent->AddRef();
m_vtx[action->piVtx[i]].massinv = rvtxmass;
m_vtx[action->piVtx[i]].iContactPart = ipart;
if (m_vtx[action->piVtx[i]].bAttached = bAttached) {
if (!is_unused(action->points))
m_vtx[action->piVtx[i]].ptAttach = action->points[i];
else
m_vtx[action->piVtx[i]].ptAttach = m_vtx[action->piVtx[i]].pos+m_pos+m_offs0;
m_vtx[action->piVtx[i]].ptAttach = (m_vtx[action->piVtx[i]].ptAttach-pbody->pos)*pbody->q;
}
}
return 1;
}
if (_action->type==pe_action_reset::type_id) {
if (m_nVtx>0) {
CTriMesh *pMesh = (CTriMesh*)m_parts[0].pPhysGeomProxy->pGeom;
int i;
for(i=0;i<m_nVtx;i++) {
if (m_vtx[i].pContactEnt) m_vtx[i].pContactEnt->Release();
m_vtx[i].pContactEnt = 0;
m_vtx[i].vel.zero();
pMesh->m_pVertices[i] = m_vtx[i].posorg;
}
for(i=0;i<pMesh->m_nTris;i++)
pMesh->m_pNormals[i] = (pMesh->m_pVertices[pMesh->m_pIndices[i*3+1]]-pMesh->m_pVertices[pMesh->m_pIndices[i*3]] ^
pMesh->m_pVertices[pMesh->m_pIndices[i*3+2]]-pMesh->m_pVertices[pMesh->m_pIndices[i*3]]).normalized();
}
return 1;
}
return CPhysicalEntity::Action(_action);
}
void CSoftEntity::StartStep(float time_interval)
{
m_timeStepPerformed = 0;
m_timeStepFull = time_interval;
}
float CSoftEntity::GetMaxTimeStep(float time_interval)
{
if (m_timeStepPerformed > m_timeStepFull-0.001f)
return time_interval;
return min(min(m_timeStepFull-m_timeStepPerformed,m_maxAllowedStep),time_interval);
}
inline int GetCheckPart(CPhysicalEntity *pent, int ipart)
{
int i = (pent->m_bProcessed_aux&0xFFFFFF) & (1<<ipart)-1;
return (pent->m_bProcessed_aux>>24) + g_bitcount[i&0xFF] + g_bitcount[i>>8&0xFF] + g_bitcount[i>>16];
}
int CSoftEntity::Step(float time_interval)
{
if (m_nVtx<=0 || m_timeStepPerformed>m_timeStepFull-0.001f)
return 1;
int i,j,j1,nEnts,i0,i1,nContactVtx,nContactVtx0,nCheckParts,iter,imask,bUnstable,iFullIter=4;
vectorf d,l,llTd,v,F,w,center,BBox0[2];
float rl,l0,rmax,windage,kr,rsep,friction=max(0.5f,1.0f-m_friction*time_interval),ks=m_ks,kdScale=1.0f;
real r2,r2new,a,b,dAd;
struct check_part {
vectorf offset;
matrix3x3f R;
box bbox;
CPhysicalEntity *pent;
int ipart;
RigidBody *pbody;
CGeometry *pGeom;
int bPrimitive;
int surface_idx;
vectorf P,L;
};
box boxent;
check_part checkParts[20];
CRayGeom aray;
intersection_params ip;
geom_contact *pcontacts;
CPhysicalEntity **pentlist,*pent;
geom_world_data gwd;
RigidBody *pbody;
g_Overlapper.Init();
boxent.size = (m_BBox[1]-m_BBox[0])*0.5f+vectorf(m_thickness,m_thickness,m_thickness)*2;
center = (m_BBox[0]+m_BBox[1])*0.5f;
boxent.bOriented = 1;
ip.bStopAtFirstTri = true;
for(i=0;i<m_nVtx;i++) if (m_vtx[i].pContactEnt && m_vtx[i].pContactEnt->m_iSimClass==7) {
m_vtx[i].pContactEnt = 0; m_vtx[i].bAttached = 0;
}
if (!m_bAwake)
return 1;
FUNCTION_PROFILER( GetISystem(),PROFILE_PHYSICS );
PHYS_ENTITY_PROFILER
nEnts = m_pWorld->GetEntitiesAround(m_BBox[0]-vectorf(m_thickness,m_thickness,m_thickness)*2,
m_BBox[1]+vectorf(m_thickness,m_thickness,m_thickness)*2, pentlist,
m_collTypes|ent_sort_by_mass|ent_ignore_noncolliding|ent_triggers, this);
for(i=j=nCheckParts=0;i<nEnts;i++) if (pentlist[i]!=this)
for(j=0,pentlist[i]->m_bProcessed_aux=nCheckParts<<24; j<pentlist[i]->m_nParts; j++) {
pentlist[i]->m_parts[j].pPhysGeomProxy->pGeom->GetBBox(&checkParts[nCheckParts].bbox);
checkParts[nCheckParts].bbox.center *= pentlist[i]->m_parts[j].scale;
checkParts[nCheckParts].bbox.size *= pentlist[i]->m_parts[j].scale;
//(pentlist[i]->m_qrot*pentlist[i]->m_parts[j].q).getmatrix(boxrope.Basis); //Q2M_IVO
boxent.Basis = matrix3x3f(pentlist[i]->m_qrot*pentlist[i]->m_parts[j].q);
checkParts[nCheckParts].offset = pentlist[i]->m_pos+pentlist[i]->m_qrot*pentlist[i]->m_parts[j].pos;
boxent.center = (center-checkParts[nCheckParts].offset)*boxent.Basis;
boxent.bOriented++;
if (box_box_overlap_check(&boxent,&checkParts[nCheckParts].bbox)) {
checkParts[nCheckParts].pent = pentlist[i];
checkParts[nCheckParts].ipart = j;
checkParts[nCheckParts].R = boxent.Basis;
pentlist[i]->m_parts[j].pPhysGeomProxy->pGeom->PrepareForRayTest(
pentlist[i]->m_parts[j].scale==1.0f ? m_thickness*2 : m_thickness*2/pentlist[i]->m_parts[j].scale);
checkParts[nCheckParts].offset -= m_pos+m_offs0;
checkParts[nCheckParts].pbody = pentlist[i]->GetRigidBody(j);
checkParts[nCheckParts].pGeom = (CGeometry*)pentlist[i]->m_parts[j].pPhysGeomProxy->pGeom;
checkParts[nCheckParts].bPrimitive = isneg(checkParts[nCheckParts].pGeom->GetPrimitiveCount()-2);
checkParts[nCheckParts].surface_idx = pentlist[i]->m_parts[j].surface_idx;
pentlist[i]->m_bProcessed_aux |= 1u<<j;
pentlist[i]->m_bProcessed = 1;
if (++nCheckParts==sizeof(checkParts)/sizeof(checkParts[0]))
goto enoughgeoms;
}
} enoughgeoms:
for(i=nContactVtx=0; i<m_nVtx; i++) if (!m_vtx[i].bAttached) { // detect collisions for free vertices
// calculate normal
for(j=m_vtx[i].iStartEdge,m_vtx[i].n.zero(); j<m_vtx[i].iEndEdge+m_vtx[i].bFullFan; j++) {
imask = j-m_vtx[i].iEndEdge>>31; j1 = j+1&imask | m_vtx[i].iStartEdge&~imask;
m_vtx[i].n +=
(m_vtx[m_edges[m_pVtxEdges[j]].ivtx[1]].pos-m_vtx[m_edges[m_pVtxEdges[j]].ivtx[0]].pos)*(iszero(i^m_edges[m_pVtxEdges[j]].ivtx[0])*2-1) ^
(m_vtx[m_edges[m_pVtxEdges[j1]].ivtx[1]].pos-m_vtx[m_edges[m_pVtxEdges[j1]].ivtx[0]].pos)*(iszero(i^m_edges[m_pVtxEdges[j1]].ivtx[0])*2-1);
}
m_vtx[i].area = m_vtx[i].n.len();
m_vtx[i].n /= m_vtx[i].area; m_vtx[i].area *= m_coverage*0.5f;
m_vtx[i].pos0 = m_vtx[i].pos;
rsep = m_thickness;
if (pent = m_vtx[i].pContactEnt) {
pbody = m_vtx[i].pContactEnt->GetRigidBody(m_vtx[i].iContactPart);
m_vtx[i].vcontact = pbody->v+(pbody->w^m_vtx[i].pos+m_pos+m_offs0-pbody->pos);
if (pent->m_bProcessed && (!m_vtx[i].bSeparating || (m_vtx[i].vel-m_vtx[i].vcontact)*m_vtx[i].ncontact<0.1f)) {
if (checkParts[GetCheckPart(m_vtx[i].pContactEnt,m_vtx[i].iContactPart)].bPrimitive) {
rsep = m_thickness*1.5f; m_vtx[i].pContactEnt = 0;
} else {
j = m_vtx[i].iContactPart;
gwd.offset = pent->m_pos-m_pos-m_offs0+pent->m_qrot*pent->m_parts[j].pos;
gwd.R = matrix3x3f(pent->m_qrot*pent->m_parts[j].q);
gwd.scale = pent->m_parts[j].scale;
aray.m_dirn = -m_vtx[i].ncontact;
aray.m_ray.origin = m_vtx[i].pos;
aray.m_ray.dir = aray.m_dirn*(m_thickness*1.5f);
gwd.iStartNode = m_vtx[i].iContactNode;
if (pent->m_parts[j].pPhysGeomProxy->pGeom->Intersect(&aray,&gwd,0,&ip,pcontacts)) {
m_vtx[i].pos = pcontacts->pt+pcontacts->n*m_thickness;
m_vtx[i].ncontact = pcontacts->n;
m_vtx[i].iContactNode = pcontacts->iNode[0];
} else
m_vtx[i].pContactEnt = 0;
}
} else
m_vtx[i].pContactEnt = 0;
}
for(j=0; j<nCheckParts; j++) {
v = checkParts[j].pbody->v+(checkParts[j].pbody->w^m_vtx[i].pos+m_pos+m_offs0-checkParts[j].pbody->pos);
if (checkParts[j].bPrimitive) {
contact acontact;
if (checkParts[j].pGeom->UnprojectSphere((m_vtx[i].pos-checkParts[j].offset)*checkParts[j].R, m_thickness,rsep, &acontact)) {
m_vtx[i].pos = checkParts[j].R*(acontact.pt+acontact.n*m_thickness)+checkParts[j].offset;
m_vtx[i].ncontact = checkParts[j].R*acontact.n;
m_vtx[i].pContactEnt = checkParts[j].pent;
m_vtx[i].iContactPart = checkParts[j].ipart;
m_vtx[i].vcontact = v;
m_vtx[i].surface_idx[1] = checkParts[j].surface_idx;
}
} else {
aray.m_ray.dir = ((v-m_vtx[i].vel)*checkParts[j].R)*m_prevTimeInterval;
aray.m_dirn = aray.m_ray.dir.normalized();
aray.m_ray.origin = (m_vtx[i].pos-checkParts[j].offset)*checkParts[j].R - aray.m_dirn*m_thickness;
aray.m_ray.dir += aray.m_dirn*m_thickness;
if (box_ray_overlap_check(&checkParts[j].bbox,&aray.m_ray)) {
gwd.scale = checkParts[j].pent->m_parts[checkParts[j].ipart].scale;
gwd.offset.zero(); gwd.R.SetIdentity();
if (checkParts[j].pent->m_parts[checkParts[j].ipart].pPhysGeomProxy->pGeom->Intersect(&aray,&gwd,0,&ip,pcontacts) &&
pcontacts->n*aray.m_dirn>0)
{
m_vtx[i].pos = checkParts[j].R*(pcontacts->pt+aray.m_dirn*m_thickness)+checkParts[j].offset;
m_vtx[i].ncontact = checkParts[j].R*pcontacts->n;
m_vtx[i].pContactEnt = checkParts[j].pent;
m_vtx[i].iContactPart = checkParts[j].ipart;
m_vtx[i].iContactNode = pcontacts->iNode[0];
m_vtx[i].vcontact = v;
imask = pcontacts->id[0]>>31;
m_vtx[i].surface_idx[1] = checkParts[j].surface_idx&imask | pcontacts->id[0]&~imask;
}
}
}
}
if (pent!=m_vtx[i].pContactEnt) {
if (pent) pent->Release();
if (m_vtx[i].pContactEnt) m_vtx[i].pContactEnt->AddRef();
}
if (m_vtx[i].pContactEnt) {
m_vtx[nContactVtx++].iSorted = i;
if ((m_vtx[i].pos0-m_vtx[i].pos).len2()>sqr(m_maxSafeStep*0.75f))
m_vtx[i].pos = m_vtx[i].pos0+(m_vtx[i].pos-m_vtx[i].pos0).normalized()*(m_maxSafeStep*0.75f);
}
} else { // synchronize attached vertices w/ hosts
pbody = m_vtx[i].pContactEnt->GetRigidBody(m_vtx[i].iContactPart);
m_vtx[i].pos = pbody->pos+pbody->q*m_vtx[i].ptAttach;
m_vtx[i].vcontact = m_vtx[i].vel = pbody->v+(pbody->w^m_vtx[i].pos-pbody->pos);
m_vtx[i].pos -= m_pos+m_offs0;
}
for(i=0; i<nCheckParts; i++)
checkParts[i].pent->m_bProcessed = 0;
for(i=0; i<m_nEdges; i++) { // calculate edge lengths
l = m_vtx[m_edges[i].ivtx[0]].pos - m_vtx[m_edges[i].ivtx[1]].pos;
m_edges[i].rlen = 1.0f/max(1E-4f,m_edges[i].len = sqrt_tpl(l.len2()));
}
for(i=0; i<m_nVtx; i++) { // apply gravity, buoyancy, wind (or water resistance)
if (!m_vtx[i].bAttached) {
if ((m_vtx[i].pos+m_pos-m_waterPlane.origin)*m_waterPlane.n<0) {
m_vtx[i].vel -= m_gravity*(m_waterDensity*m_vtx[i].volume*time_interval);
kr = m_waterResistance; w = m_waterFlow;
} else {
kr = m_airResistance; w = m_wind;
}
for(j=m_vtx[i].iStartEdge,windage=0; j<=m_vtx[i].iEndEdge; j++)
windage += ((m_vtx[m_edges[m_pVtxEdges[j]].ivtx[1]].pos-m_vtx[m_edges[m_pVtxEdges[j]].ivtx[0]].pos)*m_vtx[i].n)*
(iszero(i^m_edges[m_pVtxEdges[j]].ivtx[0])*2-1)*m_edges[m_pVtxEdges[j]].rlen;
m_vtx[i].vel += m_vtx[i].n*((m_vtx[i].n*(w-m_vtx[i].vel))*m_vtx[i].area*(windage*m_vtx[i].rnEdges+1)*kr*time_interval);
m_vtx[i].vel += m_gravity*time_interval;
}
if (m_vtx[i].pContactEnt)
m_vtx[i].vel -= m_vtx[i].ncontact*(m_vtx[i].ncontact*(m_vtx[i].vel-m_vtx[i].vcontact));
m_vtx[i].r.zero(); m_vtx[i].bSeparating = 0;
m_vtx[i].pos0=m_vtx[i].pos; m_vtx[i].vel0=m_vtx[i].vel; m_vtx[i].iSorted0=m_vtx[i].iSorted;
}
nContactVtx0 = nContactVtx;
BBox0[0] = m_BBox[0]; BBox0[1] = m_BBox[1];
reiterate:
for(i=0;i<nCheckParts;i++) checkParts[i].P=checkParts[i].L.zero();
for(i=0; i<m_nEdges; i++) { // calculate residual for the solver
i0 = m_edges[i].ivtx[0]; i1 = m_edges[i].ivtx[1];
l0 = m_edges[i].len0; rl = m_edges[i].rlen;
l = m_vtx[i0].pos - m_vtx[i1].pos;
v = m_vtx[i0].vel - m_vtx[i1].vel;
d = v*time_interval;//+m_vtx[i0].n*m_vtx[i0].shift-m_vtx[i1].n*m_vtx[i1].shift;
llTd = l*((l*d)*sqr(rl));
F = l*(rl*(l0-m_edges[i].len)*ks); // Felastic
F -= l*((v*l)*sqr(rl)*m_edges[i].kd*kdScale); // Fviscous
F += (d*(l0*rl-1)-llTd*(l0*rl))*ks; // dFelastic/dx * shift
F -= ((l*v)*(d-llTd)+l*(v*(d-llTd)))*(m_edges[i].kd*kdScale*sqr(rl)); // dFviscous/dx * shift
F *= time_interval;
m_vtx[i0].r += F*m_vtx[i0].massinv;
m_vtx[i1].r -= F*m_vtx[i1].massinv;
}
for(i=j=0; i<nContactVtx; i++) { // remove vertices that have 'separating' residuals from the contacting vertices list
i1 = m_vtx[i].iSorted;
float rn = m_vtx[i1].ncontact*m_vtx[i1].r;
if (rn>0)
m_vtx[i1].bSeparating = 1;
else {
j1 = GetCheckPart(m_vtx[i1].pContactEnt,m_vtx[i1].iContactPart);
checkParts[j1].P += m_vtx[i1].ncontact*rn;
checkParts[j1].L += m_vtx[i1].pos+m_pos-m_offs0-checkParts[j1].pbody->pos ^ m_vtx[i1].ncontact*rn;
/*imask = m_vtx[i].surface_idx[0]>>31;
float friction = max(0.0f, (m_pWorld->m_DynFrictionTable[(m_parts[0].surface_idx&imask|m_vtx[i1].surface_idx[0]&~imask)&NSURFACETYPES-1] +
m_pWorld->m_DynFrictionTable[m_vtx[i1].surface_idx[1]&NSURFACETYPES-1])*0.5f);
if (rn*friction<0) {
if ((m_vtx[i1].vel-m_vtx[i1].vcontact).len2()>sqr(rn*friction))
m_vtx[i1].vel += (m_vtx[i1].vel-m_vtx[i1].vcontact).normalized()*(rn*friction);
else
m_vtx[i1].vel = m_vtx[i1].vcontact;
}*/
m_vtx[i1].vel = m_vtx[i1].vel*friction+m_vtx[i1].vcontact*(1.0f-friction);
m_vtx[i1].r -= m_vtx[i1].ncontact*rn;
m_vtx[j++].iSorted = i1;
}
}
nContactVtx = j;
for(i=0,r2=0; i<m_nVtx; i++) {
r2+=m_vtx[i].r.len2(); m_vtx[i].d=m_vtx[i].r; m_vtx[i].P.zero();
}
iter = min(m_nMaxIters,m_nVtx);
do { // conjugate gradient solver for implicit Euler step
for(i=0; i<m_nVtx; i++)
m_vtx[i].dv = m_vtx[i].d*m_vtx[i].massinv;
for(i=0; i<m_nEdges; i++) {
i0 = m_edges[i].ivtx[0]; i1 = m_edges[i].ivtx[1];
d = m_vtx[i0].d*m_vtx[i0].massinv-m_vtx[i1].d*m_vtx[i1].massinv;
l0 = m_edges[i].len0; rl = m_edges[i].rlen;
l = m_vtx[i0].pos - m_vtx[i1].pos;
v = m_vtx[i0].vel - m_vtx[i1].vel;
llTd = l*((l*d)*sqr(rl));
F = (d*(l0*rl-1)-llTd*(l0*rl))*ks; // dFelastic/dx
F -= ((l*v)*(d-llTd)+l*(v*(d-llTd)))*(m_edges[i].kd*kdScale*sqr(rl)); // dFviscous/dx - probably not worth the calculation amount
F *= sqr(time_interval);
F += llTd*(-m_edges[i].kd*kdScale*time_interval); // dFviscous/dv
m_vtx[i0].dv -= F*m_vtx[i0].massinv;
m_vtx[i1].dv += F*m_vtx[i1].massinv;
}
for(i=0; i<nContactVtx; i++) // filter away constrained components of contacting vertices
m_vtx[m_vtx[i].iSorted].dv -= m_vtx[m_vtx[i].iSorted].ncontact*(m_vtx[m_vtx[i].iSorted].ncontact*m_vtx[m_vtx[i].iSorted].dv);
for(i=0,dAd=0; i<m_nVtx; i++)
dAd += m_vtx[i].d*m_vtx[i].dv;
if (dAd<m_accuracy*0.01f)
break;
a = min((real)100.0,r2/dAd);
for(i=0,r2new=rmax=0; i<m_nVtx; i++) {
r2new += (m_vtx[i].r -= m_vtx[i].dv*a).len2();
m_vtx[i].P += m_vtx[i].d*a;
rmax = max(rmax,m_vtx[i].r.len2());
}
b = r2new/r2; r2 = r2new;
for(i=0;i<m_nVtx;i++)
(m_vtx[i].d*=b) += m_vtx[i].r;
} while(--iter && rmax>sqr(m_accuracy));
m_vtx[0].pos += (m_vtx[0].vel+=m_vtx[0].P*m_vtx[0].massinv)*time_interval;
bUnstable = isneg(sqr(m_maxSafeStep)-m_vtx[0].pos.len2());
kr = 1.0f-m_damping*time_interval;
m_BBox[0].zero(); m_BBox[1].zero(); rmax=0;
for(i=1; i<m_nVtx; i++) {
m_vtx[i].pos += (m_vtx[i].vel+=m_vtx[i].P*m_vtx[i].massinv)*time_interval - m_vtx[0].pos;
bUnstable += isneg(sqr(m_maxSafeStep)-(m_vtx[i].pos-m_vtx[i].pos0).len2());
rmax = max(rmax,m_vtx[i].vel.len2());
m_vtx[i].vel *= kr;
m_BBox[0].x=min(m_BBox[0].x,m_vtx[i].pos.x); m_BBox[1].x=max(m_BBox[1].x,m_vtx[i].pos.x);
m_BBox[0].y=min(m_BBox[0].y,m_vtx[i].pos.y); m_BBox[1].y=max(m_BBox[1].y,m_vtx[i].pos.y);
m_BBox[0].z=min(m_BBox[0].z,m_vtx[i].pos.z); m_BBox[1].z=max(m_BBox[1].z,m_vtx[i].pos.z);
}
if (bUnstable) {
for(i=0;i<m_nVtx;i++) {
m_vtx[i].pos=m_vtx[i].pos0; m_vtx[i].vel=m_vtx[i].vel0; m_vtx[i].iSorted=m_vtx[i].iSorted0;
}
nContactVtx = nContactVtx0;
time_interval *= 0.5f; ks *= 0.49f; kdScale *= 0.7f;
if (--iFullIter>0)
goto reiterate;
else for(i=0;i<m_nVtx;i++) {
m_vtx[i].vel.zero();
m_BBox[0] = BBox0[0]-(m_pos+m_offs0);
m_BBox[1] = BBox0[1]-(m_pos+m_offs0);
}
}
pe_action_impulse ai;
ai.iApplyTime = 0;
if (m_collImpulseScale>0)
for(i=0;i<nCheckParts;i++) if (checkParts[i].P.len2()+checkParts[i].L.len2()>0 && checkParts[i].pent->GetType()==PE_LIVING) {
if (checkParts[i].P.len2()>sqr(m_maxCollImpulse)) {
a = m_maxCollImpulse/checkParts[i].P.len();
checkParts[i].P *= a; checkParts[i].L *= a;
}
ai.impulse = checkParts[i].P*m_collImpulseScale;
ai.momentum = checkParts[i].L*m_collImpulseScale;
ai.ipart = checkParts[i].ipart;
checkParts[i].pent->Action(&ai);
}
m_pos += m_vtx[0].pos; m_vtx[0].pos.zero();
m_BBox[0] += m_pos+m_offs0; m_BBox[1] += m_pos+m_offs0;
m_prevTimeInterval = time_interval;
if (m_wind.len2()*m_airResistance>0 || rmax>m_Emin) {
m_nSlowFrames = 0; m_bAwake = 1;
} else if (++m_nSlowFrames>=3)
m_bAwake = 0;
float rscale = m_parts[0].scale==1.0f ? 1.0f:1.0f/m_parts[0].scale;
box bbox;
bbox.Basis = matrix3x3f(!m_parts[0].q);
bbox.center = (m_BBox[0]+m_BBox[1])*0.5f-m_pos-m_parts[0].pos;
bbox.size = (m_BBox[1]-m_BBox[0])*(0.5f*rscale);
CTriMesh *pMesh = (CTriMesh*)m_parts[0].pPhysGeomProxy->pGeom;
((CSingleBoxTree*)pMesh->m_pTree)->SetBox(&bbox);
d = m_offs0-m_parts[0].pos;
if (m_parts[0].scale==1.0f && m_parts[0].q.w==1.0f)
for(i=0;i<m_nVtx;i++) pMesh->m_pVertices[i] = m_vtx[i].pos+d;
else
for(i=0;i<m_nVtx;i++) pMesh->m_pVertices[i] = ((m_vtx[i].pos+d)*rscale)*m_parts[0].q;
m_bMeshUpdated = 1;
//for(i=0;i<pMesh->m_nTris;i++)
// MARK_UNUSED pMesh->m_pNormals[i];
if (m_flags & pef_traceable)
m_pWorld->RepositionEntity(this, 1);
return 1;
}
int CSoftEntity::RayTrace(CRayGeom *pRay,geom_contact *&pcontacts)
{
static geom_contact g_SoftContact;
if (m_nVtx>0) {
CTriMesh *pMesh = (CTriMesh*)m_parts[0].pPhysGeom->pGeom;
prim_inters inters;
triangle atri;
int i,j;
for(i=0;i<pMesh->m_nTris;i++) {
for(j=0;j<3;j++) atri.pt[j] = m_vtx[pMesh->m_pIndices[i*3+j]].pos+m_pos+m_offs0;
atri.n = atri.pt[1]-atri.pt[0] ^ atri.pt[2]-atri.pt[0];
if (ray_tri_intersection(&pRay->m_ray,&atri,&inters)) {
pcontacts = &g_SoftContact;
pcontacts->pt = inters.pt[0];
pcontacts->t = (inters.pt[0]-pRay->m_ray.origin)*pRay->m_dirn;
pcontacts->id[0] = pMesh->m_pIds ? pMesh->m_pIds[i] : m_parts[0].surface_idx;
pcontacts->iNode[0] = i;
pcontacts->n = atri.n.normalized()*-sgnnz(atri.n*pRay->m_dirn);
return 1;
}
}
}
return 0;
}
void CSoftEntity::ApplyVolumetricPressure(const vectorf &epicenter, float kr, float rmin)
{
if (m_nVtx>0) {
CTriMesh *pMesh = (CTriMesh*)m_parts[0].pPhysGeom->pGeom;
vectorf ptc,r,n,pt[3],dP;
int i,j,idx[3];
float r2,rmin2=sqr(rmin);
kr *= m_explosionScale;
for(i=0;i<pMesh->m_nTris;i++) {
for(j=0;j<3;j++) pt[j]=m_vtx[idx[j]=pMesh->m_pIndices[i*3+j]].pos+m_pos+m_offs0;
ptc = (pt[0]+pt[1]+pt[2])*(1.0f/3); r = ptc-epicenter; r2 = r.len2();
n = pt[1]-pt[0]^pt[2]-pt[0]; n *= sgnnz(r*n);
dP = n*((n*r)*0.5f*kr/(sqrt_tpl(n.len2()*r2)*max(rmin2,r2)));
for(j=0;j<3;j++)
m_vtx[idx[j]].vel += dP*m_vtx[idx[j]].massinv;
}
m_bAwake = 1;
}
}
int CSoftEntity::GetStateSnapshot(CStream &stm,float time_back,int flags)
{
stm.WriteNumberInBits(SNAPSHOT_VERSION,4);
stm.WriteBits((BYTE*)&m_qrot0,sizeof(m_qrot0)*8);
stm.Write(m_bAwake!=0);
return 1;
}
int CSoftEntity::SetStateFromSnapshot(CStream &stm, int flags)
{
int ver=0;
bool bnz;
stm.ReadNumberInBits(ver,4);
if (ver!=SNAPSHOT_VERSION)
return 0;
if (!(flags & ssf_no_update)) {
pe_params_pos pp;
stm.ReadBits((BYTE*)&pp.q,sizeof(pp.q)*8);
SetParams(&pp);
stm.Read(bnz);
m_bAwake = bnz? 1:0;
} else
stm.Seek(stm.GetReadPos()+sizeof(quaternionf)*8+1);
return 1;
}
void CSoftEntity::DrawHelperInformation(void (*DrawLineFunc)(float*,float*), int flags)
{
CPhysicalEntity::DrawHelperInformation(DrawLineFunc,flags);
int i;
vectorf offs = m_pos+m_offs0;
if (flags & pe_helper_geometry) for(i=0;i<m_nEdges;i++)
DrawLineFunc(m_vtx[m_edges[i].ivtx[0]].pos+offs, m_vtx[m_edges[i].ivtx[1]].pos+offs);
if (flags & pe_helper_collisions) for(i=0;i<m_nVtx;i++) if (m_vtx[i].pContactEnt && !m_vtx[i].bSeparating)
DrawLineFunc(m_vtx[i].pos+offs-m_vtx[i].ncontact*m_thickness, m_vtx[i].pos+offs);
}
void CSoftEntity::GetMemoryStatistics(ICrySizer *pSizer)
{
CPhysicalEntity::GetMemoryStatistics(pSizer);
if (GetType()==PE_SOFT)
pSizer->AddObject(this, sizeof(CSoftEntity));
pSizer->AddObject(m_vtx, m_nVtx*sizeof(m_vtx[0]));
pSizer->AddObject(m_edges, m_nEdges*sizeof(m_edges[0]));
pSizer->AddObject(m_pVtxEdges, m_nEdges*2*sizeof(m_pVtxEdges[0]));
}

119
CryPhysics/softentity.h Normal file
View File

@@ -0,0 +1,119 @@
//////////////////////////////////////////////////////////////////////
//
// Soft Entity header
//
// File: softentity.h
// Description : SoftEntity class declaration
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#ifndef softentity_h
#define softentity_h
#pragma once
struct se_vertex {
~se_vertex() { if (pContactEnt) pContactEnt->Release(); }
vectorf pos,pos0,posorg;
vectorf vel,vel0;
float massinv;
float volume;
vectorf n,ncontact;
int bSeparating;
int iSorted,iSorted0;
float area;
int iStartEdge,iEndEdge,bFullFan;
float rnEdges;
CPhysicalEntity *pContactEnt;
int iContactPart;
int iContactNode;
vectorf vcontact;
int surface_idx[2];
int bAttached;
vectorf ptAttach;
vectorf P,dv,r,d;
};
struct se_edge {
int ivtx[2];
float len0;
float len,rlen;
float kd;
};
class CSoftEntity : public CPhysicalEntity {
public:
CSoftEntity(CPhysicalWorld *pworld);
virtual ~CSoftEntity();
virtual pe_type GetType() { return PE_SOFT; }
virtual int AddGeometry(phys_geometry *pgeom, pe_geomparams* params,int id=-1);
virtual void RemoveGeometry(int id);
virtual int SetParams(pe_params *_params);
virtual int GetParams(pe_params *_params);
virtual int Action(pe_action*);
virtual int GetStatus(pe_status*);
virtual int Awake(int bAwake=1,int iSource=0) { if (m_bAwake=bAwake) m_nSlowFrames=0; return 1; }
virtual int IsAwake(int ipart=-1) { return m_bAwake; }
virtual void AlertNeighbourhoodND();
virtual void StartStep(float time_interval);
virtual float GetMaxTimeStep(float time_interval);
virtual int Step(float time_interval);
virtual int RayTrace(CRayGeom *pRay, geom_contact *&pcontacts);
virtual void ApplyVolumetricPressure(const vectorf &epicenter, float kr, float rmin);
enum snapver { SNAPSHOT_VERSION = 10 };
virtual int GetStateSnapshot(CStream &stm, float time_back=0,int flags=0);
virtual int SetStateFromSnapshot(CStream &stm, int flags);
virtual void DrawHelperInformation(void (*DrawLineFunc)(float*,float*), int flags);
virtual void GetMemoryStatistics(ICrySizer *pSizer);
se_vertex *m_vtx;
se_edge *m_edges;
int *m_pVtxEdges;
int m_nVtx,m_nEdges;
vectorf m_offs0;
quaternionf m_qrot0;
int m_bMeshUpdated;
float m_timeStepFull;
float m_timeStepPerformed;
vectorf m_gravity;
float m_Emin;
float m_maxAllowedStep;
int m_bAwake,m_nSlowFrames;
float m_damping;
float m_accuracy;
int m_nMaxIters;
float m_prevTimeInterval;
float m_thickness;
float m_ks,m_kdRatio;
float m_maxSafeStep;
float m_density;
float m_coverage;
float m_friction;
float m_impulseScale;
float m_explosionScale;
float m_collImpulseScale;
float m_maxCollImpulse;
int m_collTypes;
plane m_waterPlane;
float m_waterDensity;
float m_waterDamping;
float m_waterResistance;
vectorf m_waterFlow;
float m_airResistance;
vectorf m_wind;
};
#endif

253
CryPhysics/spheregeom.cpp Normal file
View File

@@ -0,0 +1,253 @@
#include "stdafx.h"
#include "utils.h"
#include "primitives.h"
#include "unprojectionchecks.h"
#include "bvtree.h"
#include "singleboxtree.h"
#include "geometry.h"
#include "spheregeom.h"
CSphereGeom* CSphereGeom::CreateSphere(sphere *psphere)
{
m_sphere.center = psphere->center;
m_sphere.r = psphere->r;
box bbox;
bbox.Basis.SetIdentity();
bbox.center = m_sphere.center;
bbox.size.Set(m_sphere.r,m_sphere.r,m_sphere.r);
m_Tree.SetBox(&bbox);
m_Tree.Build(this);
m_minVtxDist = m_sphere.r*1E-4f;
return this;
}
int CSphereGeom::CalcPhysicalProperties(phys_geometry *pgeom)
{
pgeom->pGeom = this;
pgeom->origin = m_sphere.center;
pgeom->q.SetIdentity();
pgeom->V = 4.0f/3*pi*cube(m_sphere.r);
float x2 = sqr(m_sphere.r)*0.4f;
pgeom->Ibody.Set(x2,x2,x2);
return 1;
}
int CSphereGeom::PointInsideStatus(const vectorf &pt)
{
return (isneg((pt-m_sphere.center).len2()-sqr(m_sphere.r))<<1)-1;
}
int CSphereGeom::PrepareForIntersectionTest(geometry_under_test *pGTest, CGeometry *pCollider,geometry_under_test *pGTestColl, bool bKeepPrevContacts)
{
static short g_SphIdBuf[1];
pGTest->pGeometry = this;
pGTest->pBVtree = &m_Tree;
m_Tree.PrepareForIntersectionTest(pGTest);
pGTest->primbuf = pGTest->primbuf1 = g_SphBuf+g_SphBufPos++;
pGTest->szprimbuf = 1;
pGTest->typeprim = sphere::type;
pGTest->szprim = sizeof(sphere);
pGTest->idbuf = g_SphIdBuf;
pGTest->surfaces = 0;
pGTest->edges = 0;
pGTest->minAreaEdge = 1E10f;
return 1;
}
int CSphereGeom::PreparePrimitive(geom_world_data *pgwd,primitive *&pprim)
{
sphere *psph = g_SphBuf+g_SphBufPos;
g_SphBufPos = g_SphBufPos+1 & sizeof(g_SphBuf)/sizeof(g_SphBuf[0])-1;
psph->center = pgwd->R*m_sphere.center*pgwd->scale + pgwd->offset;
psph->r = m_sphere.r*pgwd->scale;
pprim = psph;
return sphere::type;
}
int CSphereGeom::GetPrimitiveList(int iStart,int nPrims, int typeCollider,primitive *pCollider,int bColliderLocal,
geometry_under_test *pGTest,geometry_under_test *pGTestOp, primitive *pRes,short *pResId)
{
((sphere*)pRes)->center = pGTest->R*m_sphere.center*pGTest->scale + pGTest->offset;
((sphere*)pRes)->r = m_sphere.r*pGTest->scale;
pGTest->bTransformUpdated = 0; *pResId = -1;
return 1;
}
int CSphereGeom::GetUnprojectionCandidates(int iop,const contact *pcontact, primitive *&pprim,int *&piFeature, geometry_under_test *pGTest)
{
pprim = pGTest->primbuf1;
((sphere*)pprim)->center = pGTest->R*m_sphere.center*pGTest->scale + pGTest->offset;
((sphere*)pprim)->r = m_sphere.r*pGTest->scale;
pGTest->idbuf[0] = -1;
pGTest->nSurfaces = 0;
pGTest->nEdges = 0;
return 1;
}
int CSphereGeom::FindClosestPoint(geom_world_data *pgwd, int &iPrim,int &iFeature, const vectorf &ptdst0,const vectorf &ptdst1,
vectorf *ptres, int nMaxIters)
{
vectorf center = pgwd->R*m_sphere.center*pgwd->scale + pgwd->offset;
float r = m_sphere.r*pgwd->scale;
ptres[1] = ptdst0;
if ((ptdst0-center).len2()<r*r) {
ptres[0].Set(1E10f,1E10f,1E10f);
return -1;
}
ptres[0] = center + (ptdst0-center).normalized()*r;
return 1;
}
int CSphereGeom::UnprojectSphere(vectorf center,float r,float rsep, contact *pcontact)
{
vectorf dc = center-m_sphere.center;
if (dc.len2() > sqr(m_sphere.r+rsep))
return 0;
pcontact->n = dc.normalized();
pcontact->t = dc*pcontact->n-m_sphere.r-r;
pcontact->pt = m_sphere.center+pcontact->n*m_sphere.r;
return 1;
}
float CSphereGeom::CalculateBuoyancy(const plane *pplane, const geom_world_data *pgwd, vectorf &massCenter)
{
float r=m_sphere.r*pgwd->scale,x;
vectorf n=pplane->n, center=pgwd->R*m_sphere.center+pgwd->offset;
massCenter = center;
x = (pplane->origin-center)*n;
if (x>r)
return 0;
if (x<-r)
return (4.0f/3)*pi*cube(r);
massCenter += n*(pi*0.5f*(x*x*(r*r-x*x*0.5f)-r*r*r*r*0.5f)-x);
return pi*((2.0f/3)*cube(r)+x*(r*r-x*x*(1.0f/3)));
}
void CSphereGeom::CalculateMediumResistance(const plane *pplane, const geom_world_data *pgwd, vectorf &dPres,vectorf &dLres)
{
vectorf center,v,vn,axisx,axisy,n;
float r,x,vxn,vxninv,nv,cx,ry,l,lx,ly,circ_S,circ_x,ell_S,ell_x,S;
center = pgwd->R*m_sphere.center*pgwd->scale+pgwd->offset;
r = m_sphere.r*pgwd->scale; n = pplane->n;
v = pgwd->v + (pgwd->w ^ center-pgwd->centerOfMass);
x = (pplane->origin-center)*n;
if (fabsf(x)>r) {
dLres.zero(); dPres.zero();
if (x>r)
dPres = v*(-pi*r*r);
return;
}
vn = v.normalized();
axisy = vn^n; vxn = axisy.len();
if (vxn<0.01f) {
//axisy = vn.orthogonal().normalized(); l = sgnnz(x)*r;
axisy = GetOrthogonal(vn).normalized(); l = sgnnz(x)*r;
} else { // l - water plane - v+ plane intersection line along x
axisy *= (vxninv=1.0f/vxn); l = x*vxninv;
}
axisx = axisy^vn;
nv = n*v;
cx = x*vxn; // ellipse center along x
ry = max(0.001f,sqrt_tpl(r*r-x*x)); // ellipse radius along y
lx = max(-r*0.999f,min(r*0.999f,l)); ly = sqrt_tpl(r*r-lx*lx);
circ_S = (lx*ly+r*r*(pi*0.5f+asin_tpl(lx/r)))*0.5f;
circ_x = cube(ly)*(-1.0f/3);
lx = max(-ry*0.999f,min(ry*0.999f,(l-cx)/max(0.001f,fabs_tpl(nv)))); ly = sqrt_tpl(ry*ry-lx*lx);
ell_S = (lx*ly+ry*ry*(pi*0.5f+asin_tpl(lx/ry)*sgnnz(nv)))*fabs_tpl(nv)*0.5f;
ell_x = cube(ly)*(-1.0f/3)*nv+cx;
S = circ_S+ell_S;
x = (circ_x*circ_S+ell_x*ell_S)/S;
dPres = -v*S;
center += axisx*x + vn*sqrt_tpl(max(0.0f,r*r-x*x));
dLres = center-pgwd->centerOfMass ^ dPres;
}
void CSphereGeom::CalcVolumetricPressure(geom_world_data *gwd, const vectorf &epicenter,float k,float rmin,
const vectorf &centerOfMass, vectorf &P,vectorf &L)
{
vectorf dc = gwd->R*m_sphere.center*gwd->scale+gwd->offset-epicenter;
P += dc*(k/(dc.len()*max(dc.len2(),sqr(rmin))));
}
int CSphereGeom::DrawToOcclusionCubemap(const geom_world_data *pgwd, int iStartPrim,int nPrims, int iPass, int *pGrid[6],int nRes,
float rmin,float rmax,float zscale)
{
vectorf center=pgwd->R*m_sphere.center*pgwd->scale+pgwd->offset, axisx,axisy,pt[8];
float x=m_sphere.r*pgwd->scale,y=0;
const float step=1.0f/sqrt2;
//axisx = center.orthogonal().normalized(); axisy = (axisx^center).normalized();
axisx = GetOrthogonal(center).normalized(); axisy = (axisx^center).normalized();
for(int i=0;i<8;i++) {
pt[i] = center + axisx*x + axisy*y;
x = (x-y)*(1.0f/sqrt2);
y = x+y*sqrt2;
}
RasterizePolygonIntoCubemap(pt,8, iPass, pGrid,nRes, rmin,rmax,zscale);
return 1;
}
void CSphereGeom::DrawWireframe(void (*DrawLineFunc)(float*,float*), geom_world_data *gwd, int iLevel)
{
if (iLevel==0) {
int i,ix,iy,iz;
vectorf pt0,pt1;
const float stepcos=cry_cosf(pi/8),stepsin=cry_sinf(pi/8);
for(iz=0;iz<3;iz++) {
ix = inc_mod3[iz]; iy = dec_mod3[iz];
pt0[ix]=m_sphere.r*gwd->scale; pt0[iy]=pt0[iz]=pt1[iz]=0;
for(i=0;i<16;i++) {
pt1[ix] = pt0[ix]*stepcos-pt0[iy]*stepsin;
pt1[iy] = pt0[ix]*stepsin+pt0[iy]*stepcos;
DrawLineFunc(gwd->R*(pt0+m_sphere.center)+gwd->offset, gwd->R*(pt1+m_sphere.center)+gwd->offset);
pt0 = pt1;
}
}
} else {
BV *pbbox;
ResetGlobalPrimsBuffers();
m_Tree.GetNodeBV(gwd->R,gwd->offset,gwd->scale, pbbox);
DrawBBox(DrawLineFunc,gwd, &m_Tree,(BBox*)pbbox,iLevel-1);
}
}
void CSphereGeom::GetMemoryStatistics(ICrySizer *pSizer)
{
pSizer->AddObject(this, sizeof(CSphereGeom));
}
void CSphereGeom::Save(CMemStream &stm)
{
stm.Write(m_sphere);
m_Tree.Save(stm);
}
void CSphereGeom::Load(CMemStream &stm)
{
stm.Read(m_sphere);
m_Tree.Load(stm,this);
}

43
CryPhysics/spheregeom.h Normal file
View File

@@ -0,0 +1,43 @@
#ifndef spheregeom_h
#define spheregeom_h
#pragma once
class CSphereGeom : public CPrimitive {
public:
CSphereGeom() { m_iCollPriority = 3; m_minVtxDist = 0; }
CSphereGeom* CreateSphere(sphere *pcyl);
virtual int GetType() { return GEOM_SPHERE; }
virtual void GetBBox(box *pbox) { m_Tree.GetBBox(pbox); }
virtual int CalcPhysicalProperties(phys_geometry *pgeom);
virtual int FindClosestPoint(geom_world_data *pgwd, int &iPrim,int &iFeature, const vectorf &ptdst0,const vectorf &ptdst1,
vectorf *ptres, int nMaxIters);
virtual int PointInsideStatus(const vectorf &pt);
virtual float CalculateBuoyancy(const plane *pplane, const geom_world_data *pgwd, vectorf &massCenter);
virtual void CalculateMediumResistance(const plane *pplane, const geom_world_data *pgwd, vectorf &dPres,vectorf &dLres);
virtual void CalcVolumetricPressure(geom_world_data *gwd, const vectorf &epicenter,float k,float rmin,
const vectorf &centerOfMass, vectorf &P,vectorf &L);
virtual int DrawToOcclusionCubemap(const geom_world_data *pgwd, int iStartPrim,int nPrims, int iPass, int *pGrid[6],int nRes,
float rmin,float rmax,float zscale);
virtual CBVTree *GetBVTree() { return &m_Tree; }
virtual int UnprojectSphere(vectorf center,float r,float rsep, contact *pcontact);
virtual int GetPrimitive(int iPrim, primitive *pprim) { *(sphere*)pprim = m_sphere; return sizeof(sphere); }
virtual void DrawWireframe(void (*DrawLineFunc)(float*,float*), geom_world_data *gwd, int iLevel);
virtual int PrepareForIntersectionTest(geometry_under_test *pGTest, CGeometry *pCollider,geometry_under_test *pGTestColl, bool bKeepPrevContacts=false);
virtual int PreparePrimitive(geom_world_data *pgwd,primitive *&pprim);
virtual int GetPrimitiveList(int iStart,int nPrims, int typeCollider,primitive *pCollider,int bColliderLocal,
geometry_under_test *pGTest,geometry_under_test *pGTestOp, primitive *pRes,short *pResId);
virtual int GetUnprojectionCandidates(int iop,const contact *pcontact, primitive *&pprim,int *&piFeature, geometry_under_test *pGTest);
virtual void GetMemoryStatistics(ICrySizer *pSizer);
virtual void Save(CMemStream &stm);
virtual void Load(CMemStream &stm);
sphere m_sphere;
CSingleBoxTree m_Tree;
};
#endif

2180
CryPhysics/trimesh.cpp Normal file

File diff suppressed because it is too large Load Diff

111
CryPhysics/trimesh.h Normal file
View File

@@ -0,0 +1,111 @@
#ifndef trimesh_h
#define trimesh_h
struct trinfo {
index_t ibuddy[3];
};
struct border_trace {
vectorf *pt;
int (*itri)[2];
float *seglen;
int npt,szbuf;
vectorf pt_end;
int itri_end;
int iedge_end;
float end_dist2;
int iMark,nLoop;
vectorr n_sum[2];
vectorf n_best;
int ntris[2];
};
class CTriMesh : public CGeometry {
public:
CTriMesh();
virtual ~CTriMesh();
CTriMesh* CreateTriMesh(strided_pointer<const vectorf> pVertices,index_t *pIndices,const short *pIds,int nTris, int flags,
bool bCanSortTriangles=false,bool bCopyVertices=true, int nMinTrisPerNode=2,int nMaxTrisPerNode=4, float favorAABB=1.0f);
virtual int GetType() { return GEOM_TRIMESH; }
virtual int Intersect(IGeometry *pCollider, geom_world_data *pdata1,geom_world_data *pdata2, intersection_params *pparams, geom_contact *&pcontacts);
virtual void GetBBox(box *pbox) { m_pTree->GetBBox(pbox); }
virtual int FindClosestPoint(geom_world_data *pgwd, int &iPrim,int &iFeature, const vectorf &ptdst0,const vectorf &ptdst1,
vectorf *ptres, int nMaxIters=10);
virtual int CalcPhysicalProperties(phys_geometry *pgeom);
virtual int PointInsideStatus(const vectorf &pt);
virtual void DrawWireframe(void (*DrawLineFunc)(float*,float*),geom_world_data *gwd, int iLevel);
virtual void CalcVolumetricPressure(geom_world_data *gwd, const vectorf &epicenter,float k,float rmin,
const vectorf &centerOfMass, vectorf &P,vectorf &L);
virtual float CalculateBuoyancy(const plane *pplane, const geom_world_data *pgwd, vectorf &massCenter);
virtual void CalculateMediumResistance(const plane *pplane, const geom_world_data *pgwd, vectorf &dPres,vectorf &dLres);
virtual int GetPrimitiveId(int iPrim,int iFeature) { return m_pIds ? m_pIds[iPrim]:-1; }
virtual int IsConvex(float tolerance);
virtual void PrepareForRayTest(float raylen);
virtual int DrawToOcclusionCubemap(const geom_world_data *pgwd, int iStartPrim,int nPrims, int iPass, int *pGrid[6],int nRes,
float rmin,float rmax,float zscale);
virtual CBVTree *GetBVTree() { return m_pTree; }
virtual int GetPrimitiveCount() { return m_nTris; }
virtual int GetPrimitive(int iPrim, primitive *pprim) {
if ((unsigned int)iPrim>=(unsigned int)m_nTris)
return 0;
((triangle*)pprim)->pt[0] = m_pVertices[m_pIndices[iPrim*3+0]];
((triangle*)pprim)->pt[1] = m_pVertices[m_pIndices[iPrim*3+1]];
((triangle*)pprim)->pt[2] = m_pVertices[m_pIndices[iPrim*3+2]];
((triangle*)pprim)->n = m_pNormals[iPrim];
return sizeof(triangle);
}
virtual int GetFeature(int iPrim,int iFeature, vectorf *pt);
virtual int PreparePrimitive(geom_world_data *pgwd,primitive *&pprim);
virtual void RemapFaceIds(short *pMap,int sz) { if (m_pIds) for(int i=0;i<m_nTris;i++) m_pIds[i]=pMap[min(m_pIds[i],sz-1)]; }
virtual void GetMemoryStatistics(ICrySizer *pSizer);
virtual void Save(CMemStream &stm);
virtual void Load(CMemStream &stm);
virtual int PrepareForIntersectionTest(geometry_under_test *pGTest, CGeometry *pCollider,geometry_under_test *pGTestColl, bool bKeepPrevContacts=false);
virtual int RegisterIntersection(primitive *pprim1,primitive *pprim2, geometry_under_test *pGTest1,geometry_under_test *pGTest2,
prim_inters *pinters);
virtual void CleanupAfterIntersectionTest(geometry_under_test *pGTest);
virtual int GetPrimitiveList(int iStart,int nPrims, int typeCollider,primitive *pCollider,int bColliderLocal,
geometry_under_test *pGTest,geometry_under_test *pGTestOp, primitive *pRes,short *pResId);
virtual int GetUnprojectionCandidates(int iop,const contact *pcontact, primitive *&pprim,int *&piFeature, geometry_under_test *pGTest);
virtual int PreparePolygon(coord_plane *psurface, int iPrim,int iFeature, geometry_under_test *pGTest, vector2df *&ptbuf,
int *&pVtxIdBuf,int *&pEdgeIdBuf);
virtual int PreparePolyline(coord_plane *psurface, int iPrim,int iFeature, geometry_under_test *pGTest, vector2df *&ptbuf,
int *&pVtxIdBuf,int *&pEdgeIdBuf);
int GetEdgeByBuddy(int itri,int itri_buddy) {
int iedge=0,imask;
imask = m_pTopology[itri].ibuddy[1]-itri_buddy; imask = imask-1>>31 ^ imask>>31; iedge = 1&imask;
imask = m_pTopology[itri].ibuddy[2]-itri_buddy; imask = imask-1>>31 ^ imask>>31; iedge = iedge&~imask | 2&imask;
return iedge;
}
int GetNeighbouringEdgeId(int vtxid, int ivtx);
void PrepareTriangle(int itri,triangle *ptri, const geometry_under_test *pGTest);
int TraceTriangleInters(int iop, primitive *pprims[], int idx_buddy,int type_buddy, prim_inters *pinters,
geometry_under_test *pGTest, border_trace *pborder);
void HashTrianglesToPlane(const coord_plane &hashplane, const vector2df &hashsize, grid &hashgrid,index_t *&pHashGrid,index_t *&pHashData,float cellsize=0);
CBVTree *m_pTree;
trinfo *m_pTopology;
index_t *m_pIndices;
short *m_pIds;
strided_pointer<vectorf> m_pVertices;
vectorf *m_pNormals;
int m_nTris,m_nVertices;
int m_nMaxVertexValency;
int m_flags;
index_t *m_pHashGrid[3],*m_pHashData[3];
grid m_hashgrid[3];
int m_nHashPlanes;
int m_bConvex[4];
float m_ConvexityTolerance[4];
int m_bMultipart;
};
#endif

View File

@@ -0,0 +1,93 @@
#ifndef unprojectionchecks_h
#define unprojectionchecks_h
struct unprojection_mode {
unprojection_mode() { bCheckContact=0; }
int imode;
vectorf dir; // direction or rotation axis
vectorf center; // center of rotation
float vel; // linear or angular velocity
float tmax; // maximum unprojection length (not time)
float minPtDist; // tolerance value
int bCheckContact;
matrix3x3f R0;
vectorf offset0;
};
typedef int (*unprojection_check)(unprojection_mode*, const primitive*,int,const primitive*,int, contact*, geom_contact_area*);
int default_unprojection(unprojection_mode*, const primitive*,int,const primitive*,int, contact*, geom_contact_area*);
int tri_tri_lin_unprojection(unprojection_mode *pmode, const triangle *ptri1,int iFeature1,const triangle *ptri2,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int tri_box_lin_unprojection(unprojection_mode *pmode, const triangle *ptri,int iFeature1,const box *pbox,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int box_tri_lin_unprojection(unprojection_mode *pmode, const box *pbox,int iFeature1,const triangle *ptri,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int tri_cylinder_lin_unprojection(unprojection_mode *pmode, const triangle *ptri,int iFeature1,const cylinder *pcyl,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int cylinder_tri_lin_unprojection(unprojection_mode *pmode, const cylinder *pcyl,int iFeature1,const triangle *ptri,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int tri_sphere_lin_unprojection(unprojection_mode *pmode, const triangle *ptri,int iFeature1,const sphere *psphere,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int sphere_tri_lin_unprojection(unprojection_mode *pmode, const sphere *psphere,int iFeature1,const triangle *ptri,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int tri_ray_lin_unprojection(unprojection_mode *pmode, const triangle *ptri,int iFeature1,const ray *pray,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int ray_tri_lin_unprojection(unprojection_mode *pmode, const ray *pray,int iFeature1,const triangle *ptri,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int tri_plane_lin_unprojection(unprojection_mode *pmode, const triangle *ptri,int iFeature1,const plane *pplane,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int plane_tri_lin_unprojection(unprojection_mode *pmode, const plane *pplane,int iFeature1,const triangle *ptri,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int box_box_lin_unprojection(unprojection_mode *pmode, const box *pbox1,int iFeature1, const box *pbox2,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int box_cylinder_lin_unprojection(unprojection_mode *pmode, const box *pbox,int iFeature1,const cylinder *pcyl,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int cylinder_box_lin_unprojection(unprojection_mode *pmode, const cylinder *pcyl,int iFeature1,const box *pbox,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int box_sphere_lin_unprojection(unprojection_mode *pmode, const box *pbox,int iFeature1,const sphere *psph,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int sphere_box_lin_unprojection(unprojection_mode *pmode, const sphere *psph,int iFeature1,const box *pbox,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int cyl_cyl_lin_unprojection(unprojection_mode *pmode, const cylinder *pcyl1,int iFeature1,const cylinder *pcyl2,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int cylinder_sphere_lin_unprojection(unprojection_mode *pmode, const cylinder *pbox,int iFeature1,const sphere *psph,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int sphere_cylinder_lin_unprojection(unprojection_mode *pmode, const sphere *psph,int iFeature1,const cylinder *pcyl,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int sphere_sphere_lin_unprojection(unprojection_mode *pmode, const sphere *psph1,int iFeature1, const sphere *psph2,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int tri_tri_rot_unprojection(unprojection_mode *pmode, const triangle *ptri1,int iFeature1,const triangle *ptri2,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int tri_ray_rot_unprojection(unprojection_mode *pmode, const triangle *ptri,int iFeature1,const ray *pray,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int ray_tri_rot_unprojection(unprojection_mode *pmode, const ray *pray,int iFeature1,const triangle *ptri,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int cyl_ray_rot_unprojection(unprojection_mode *pmode, const cylinder *pcyl,int iFeature1,const ray *pray,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int ray_cyl_rot_unprojection(unprojection_mode *pmode, const ray *pray,int iFeature1,const cylinder *pcyl,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int box_ray_rot_unprojection(unprojection_mode *pmode, const box *pbox,int iFeature1, const ray *pray,int iFeature2,
contact *pcontact, geom_contact_area *parea);
int ray_box_rot_unprojection(unprojection_mode *pmode, const ray *pray,int iFeature1, const box *pbox,int iFeature2,
contact *pcontact, geom_contact_area *parea);
class CUnprojectionChecker {
public:
CUnprojectionChecker();
int Check(unprojection_mode *pmode, int type1,int type2, const primitive *prim1,int iFeature1,const primitive *prim2,int iFeature2,
contact *pcontact, geom_contact_area *parea=0)
{
return table[pmode->imode][type1][type2](pmode, prim1,iFeature1,prim2,iFeature2, pcontact, parea);
}
int CheckExists(int imode, int type1,int type2) {
return table[imode][type1][type2]!=default_unprojection;
}
unprojection_check table[2][NPRIMS][NPRIMS];
};
extern CUnprojectionChecker g_Unprojector;
#endif

1270
CryPhysics/utils.cpp Normal file

File diff suppressed because it is too large Load Diff

344
CryPhysics/utils.h Normal file
View File

@@ -0,0 +1,344 @@
//////////////////////////////////////////////////////////////////////
//
// Utils header
//
// File: utils.h
// Description : Various utility functions definitions
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#ifndef utils_h
#define utils_h
#include <math.h>
#include "Cry_Math.h"
using namespace primitives;
void ExtrudeBox(const primitives::box *pbox, const vectorf& dir,float step, primitives::box *pextbox);
#define USE_MATRIX_POOLS
#include "matrixnm.h"
#include "vectorn.h"
#include "quotient.h"
#include "polynomial.h"
#include "primitives.h"
const float fmag = 1.5f*(1<<23);
union floatint {
float fval;
int ival;
};
#if defined(WIN64) || defined(LINUX64)
const int imag = (23+127)<<23 | 1<<22;
int float2int(float x);
#elif defined(LINUX32)
const int imag = (23+127)<<23 | 1<<22;
inline int float2int(float x) {
floatint u;
u.fval = x+fmag;
return u.ival-imag;
}
#else //WIN64
__declspec(naked) inline int64 GetTicks() {
__asm rdtsc
__asm ret
}
const int imag = -((23+127)<<23 | 1<<22);
// had to rewrite in assembly, since it's impossible to tell the compiler that in this case
// addition is not associative, i.e. (x+0.5)+fmag!=x+(fmag+0.5)
__declspec(naked) inline int float2int(float x)
{ __asm {
fld [esp+4]
fadd fmag
mov eax, imag
fstp [esp-4]
add eax, [esp-4]
ret
}}
#endif //WIN64
int qhull(strided_pointer<vectorf> pts, int npts, index_t*& pTris);
struct ptitem2d {
vector2df pt;
ptitem2d *next,*prev;
int iContact;
};
struct edgeitem {
ptitem2d *pvtx;
ptitem2d *plist;
edgeitem *next,*prev;
float area,areanorm2;
edgeitem *next1,*prev1;
int idx;
};
int qhull2d(ptitem2d *pts,int nVtx, edgeitem *edges);
real ComputeMassProperties(strided_pointer<const vectorf> points, const index_t *faces, int nfaces, vectorr &center,matrix3x3 &I);
template<class ftype,int stridei,int stridej>
void OffsetInertiaTensor(Matrix33_tpl<ftype,stridei,stridej> &I,const Vec3_tpl<ftype> &center,ftype M)
{
I(0,0) += M*(center.y*center.y + center.z*center.z);
I(1,1) += M*(center.x*center.x + center.z*center.z);
I(2,2) += M*(center.x*center.x + center.y*center.y);
I(1,0) = I(0,1) = I(0,1)-M*center.x*center.y;
I(2,0) = I(0,2) = I(0,2)-M*center.x*center.z;
I(2,1) = I(1,2) = I(1,2)-M*center.y*center.z;
}
void ComputeMeshEigenBasis(strided_pointer<const vectorf> pVertices,const index_t *pIndices,int nTris, vectorr *eigen_axes,vectorr &center);
enum booltype { bool_intersect=1 };
int boolean2d(booltype type, vector2df *ptbuf1,int npt1, vector2df *ptbuf2,int npt2,int bClosed, vector2df *&ptbuf,int *&pidbuf);
real RotatePointToPlane(const vectorr &pt, const vectorr &axis,const vectorr &center, const vectorr &n,const vectorr &origin);
inline void LeftOffsetSpatialMatrix(matrixf &mtx, const vectorf &offset){
matrix3x3f rmtx;
matrix3x3in6x6f &A((matrix3x3in6x6f&)mtx.data[0]),&B((matrix3x3in6x6f&)mtx.data[3]),
&C((matrix3x3in6x6f&)mtx.data[18]),&D((matrix3x3in6x6f&)mtx.data[21]);
C += (crossproduct_matrix(offset, rmtx)*=A);
D += (crossproduct_matrix(offset, rmtx)*=B);
}
inline void RightOffsetSpatialMatrix(matrixf &mtx, const vectorf &offset){
matrix3x3f rmtx,tmtx;
matrix3x3in6x6f &A((matrix3x3in6x6f&)mtx.data[0]),&B((matrix3x3in6x6f&)mtx.data[3]),
&C((matrix3x3in6x6f&)mtx.data[18]),&D((matrix3x3in6x6f&)mtx.data[21]);
A += ((tmtx=B)*=crossproduct_matrix(offset,rmtx));
C += ((tmtx=D)*=rmtx);
}
inline void SpatialTranspose(matrixf &src, matrixf& dst) {
int i,j;
dst.nRows = src.nCols; dst.nCols = src.nRows;
for(i=0;i<src.nRows;i++) for(j=0;j<3;j++) {
dst[j][i] = src[i][j+3];
dst[j+3][i] = src[i][j];
}
}
template<class ftype> inline Vec3_tpl<ftype> cross_with_ort(const Vec3_tpl<ftype> &vec, int iz) {
Vec3_tpl<ftype> res(zero);
int ix=inc_mod3[iz], iy=dec_mod3[iz];
res[iz]=0; res[ix]=vec[iy]; res[iy]=-vec[ix];
return res;
}
void get_xqs_from_matrices(float *pMtx3x3,float *pMtx3x3T,float *pMtx4x4,float *pMtx4x4T, vectorf &pos,quaternionf &q,float &scale);
int BreakPolygon(vector2df *ptSrc,int nPt, int nCellx,int nCelly, int maxPatchTris, vector2df *&ptout,int *&nPtOut,
float jointhresh=0.5f,int seed=-1);
void RasterizePolygonIntoCubemap(const vectorf *pt,int npt, int iPass, int *pGrid[6],int nRes, float rmin,float rmax,float zscale);
void GrowAndCompareCubemaps(int *pGridOcc[6],int *pGrid[6],int nRes, int nGrow, int &nCells,int &nOccludedCells);
void CalcMediumResistance(const vectorf *ptsrc,int npt, const vectorf& n, const plane &waterPlane,
const vectorf &vworld,const vectorf &wworld,const vectorf &com, vectorf &P,vectorf &L);
int CoverPolygonWithCircles(strided_pointer<vector2df> pt,int npt,bool bConsecutive, const vector2df &center, vector2df *&centers,
float *&radii, float minCircleRadius);
int ChoosePrimitiveForMesh(strided_pointer<const vectorf> pVertices,const index_t *pIndices,int nTris, const vectorr *eigen_axes,const vectorr &center,
int flags, float tolerance, primitive *&pprim);
void ExtrudeBox(const box *pbox, const vectorf& dir,float step, box *pextbox);
template<class CellChecker>
int DrawRayOnGrid(primitives::grid *pgrid, vectorf &origin,vectorf &dir, CellChecker &cell_checker)
{
int i,ishort,ilong,bStep,bPrevStep,ilastcell;
float dshort,dlong,frac;
quotientf tx[2],ty[2],t[2];
vector2di istep,icell,idirsgn;
// crop ray with grid bounds
idirsgn.set(sgnnz(dir.x),sgnnz(dir.y));
i = idirsgn.x;
tx[1-i>>1].set(-origin.x*i, dir.x*i);
tx[1+i>>1].set((pgrid->size.x*pgrid->step.x-origin.x)*i, dir.x*i);
i = idirsgn.y;
ty[1-i>>1].set(-origin.y*i, dir.y*i);
ty[1+i>>1].set((pgrid->size.y*pgrid->step.y-origin.y)*i, dir.y*i);
t[0] = max(t[0].set(0,1),max(tx[0],ty[0]));
t[1] = min(t[1].set(1,1),min(tx[1],ty[1]));
if (t[0]>=t[1])
return 0;
if (t[0]>0)
origin += dir*t[0].val();
if (t[0]>0 || t[1]<1)
dir *= (t[1]-t[0]).val();
ilong = isneg(fabs_tpl(dir.x)-fabs_tpl(dir.y));
ishort = ilong^1;
dshort = fabs_tpl(dir[ishort]); dlong = fabs_tpl(dir[ilong]);
istep[ilong] = idirsgn[ilong];
istep[ishort] = idirsgn[ishort];
icell.set(float2int(origin.x*pgrid->stepr.x-0.5f), float2int(origin.y*pgrid->stepr.y-0.5f));
ilastcell = float2int((origin.y+dir.y)*pgrid->stepr.y-0.5f)<<16 | float2int((origin.x+dir.x)*pgrid->stepr.x-0.5f);
if (cell_checker.check_cell(icell,ilastcell) || (icell.y<<16|icell.x)==ilastcell)
return 1;
t[0].set((icell[ilong]+(istep[ilong]+1>>1))*pgrid->step[ilong]-origin[ilong], dir[ilong]);
frac = (origin[ishort]+dir[ishort]*t[0].val() - icell[ishort]*pgrid->step[ishort])*pgrid->stepr[ishort];
i = isneg(dir[ishort]);
frac = i+frac*(1-(i<<1));
if (frac>1.0f) {
icell[ishort] += istep[ishort];
if (cell_checker.check_cell(icell,ilastcell) || (icell.y<<16|icell.x)==ilastcell)
return 1;
frac -= 1;
}
frac *= dlong;
icell[ilong] += istep[ilong];
bPrevStep = 0;
do {
if (cell_checker.check_cell(icell,ilastcell) || (icell.y<<16|icell.x)==ilastcell)
return 1;
frac += dshort*(bPrevStep^1); bStep = isneg(dlong-frac);
icell[ishort] += bStep*istep[ishort]; frac -= dlong*bStep;
icell[ilong] += istep[ilong]&~-bStep;
bPrevStep = bStep;
} while(true);
return 0;
}
int bin2ascii(const unsigned char *pin,int sz, unsigned char *pout);
int ascii2bin(const unsigned char *pin,int sz, unsigned char *pout);
template<class T> inline T *_align16(T *ptr) { return (T*)(((INT_PTR)ptr-1&~15)+16); }
#if !defined(LINUX)
template<class dtype> bool is_valid(const dtype &op) { return is_valid(op|op); }
inline bool is_valid(float op) { return op*op>=0 && op*op<1E30f; }
inline bool is_valid(int op) { return true; }
inline bool is_valid(unsigned int op) { return true; }
#endif
void WritePacked(CStream &stm, int num);
void WritePacked(CStream &stm, uint64 num);
void ReadPacked(CStream &stm,int &num);
void ReadPacked(CStream &stm,uint64 &num);
void WriteCompressedPos(CStream &stm, const vectorf &pos, bool bCompress=true);
void ReadCompressedPos(CStream &stm, vectorf &pos, bool &bWasCompressed);
vectorf CompressPos(const vectorf &pos);
const int CMP_QUAT_SZ = 49;
void WriteCompressedQuat(CStream &stm, const quaternionf &q);
void ReadCompressedQuat(CStream &stm,quaternionf &q);
quaternionf CompressQuat(const quaternionf &q);
const int CMP_VEL_SZ = 48;
inline void WriteCompressedVel(CStream &stm, const vectorf &vel, const float maxvel) {
stm.Write((short)max(-32768,min(32767,float2int(vel.x*(32767.0f/maxvel)))));
stm.Write((short)max(-32768,min(32767,float2int(vel.y*(32767.0f/maxvel)))));
stm.Write((short)max(-32768,min(32767,float2int(vel.z*(32767.0f/maxvel)))));
}
inline void ReadCompressedVel(CStream &stm, vectorf &vel, const float maxvel) {
short i;
stm.Read(i); vel.x = i*(maxvel/32767.0f);
stm.Read(i); vel.y = i*(maxvel/32767.0f);
stm.Read(i); vel.z = i*(maxvel/32767.0f);
}
inline vectorf CompressVel(const vectorf &vel, const float maxvel) {
vectorf res;
res.x = max(-32768,min(32767,float2int(vel.x*(32767.0f/maxvel)))) * (maxvel/32767.0f);
res.y = max(-32768,min(32767,float2int(vel.y*(32767.0f/maxvel)))) * (maxvel/32767.0f);
res.z = max(-32768,min(32767,float2int(vel.z*(32767.0f/maxvel)))) * (maxvel/32767.0f);
return res;
}
inline void WriteCompressedFloat(CStream &stm, float f, const float maxval,const int nBits) {
const int imax = (1<<nBits-1)-1;
stm.WriteNumberInBits(max(-imax-1,min(imax,float2int(f*(imax/maxval)))),nBits);
}
inline void ReadCompressedFloat(CStream &stm, float &f, const float maxval,const int nBits) {
const int imax = (1<<nBits-1)-1;
unsigned int num;
stm.ReadNumberInBits(num,nBits);
f = ((int)num | ((int)num<<32-nBits & 1<<31)>>31-nBits)*(maxval/imax);
}
inline float CompressFloat(float f,const float maxval,const int nBits) {
const int imax = (1<<nBits-1)-1;
return max(-imax-1,min(imax,float2int(f*(imax/maxval)))) * (maxval/imax);
}
inline intptr_t iszero_mask(void *ptr) { return (intptr_t)ptr>>sizeof(intptr_t)*8-1 ^ (intptr_t)ptr-1>>sizeof(intptr_t)*8-1; }
template<class ftype> inline int AABB_overlap(Vec3_tpl<ftype> *BBox0,Vec3_tpl<ftype> *BBox1) {
return isneg(fabs_tpl(BBox0[0].x+BBox0[1].x-BBox1[0].x-BBox1[1].x) - (BBox0[1].x-BBox0[0].x)-(BBox1[1].x-BBox1[0].x)) &
isneg(fabs_tpl(BBox0[0].y+BBox0[1].y-BBox1[0].y-BBox1[1].y) - (BBox0[1].y-BBox0[0].y)-(BBox1[1].y-BBox1[0].y)) &
isneg(fabs_tpl(BBox0[0].z+BBox0[1].z-BBox1[0].z-BBox1[1].z) - (BBox0[1].z-BBox0[0].z)-(BBox1[1].z-BBox1[0].z));
}
extern int g_bitcount[256];
const int SINCOSTABSZ = 1024, SINCOSTABSZ_LOG2 = 10;
extern float g_costab[SINCOSTABSZ],g_sintab[SINCOSTABSZ];
// uncomment the following block to effectively disable validations
/*#define VALIDATOR_LOG(pLog,str)
#define VALIDATORS_START
#define VALIDATOR(member)
#define VALIDATOR_NORM(member)
#define VALIDATOR_RANGE(member,minval,maxval)
#define VALIDATOR_RANGE2(member,minval,maxval)
#define VALIDATORS_END
#define ENTITY_VALIDATE(strSource,pStructure)*/
#if defined(WIN64) || defined(LINUX64)
#define DoBreak {assert(0);}
#else
#define DoBreak { DEBUG_BREAK; }
#endif
#if defined LINUX
#include "validator.h"
#else
#define VALIDATOR_LOG(pLog,str) pLog->Log(str) //OutputDebugString(str)
#define VALIDATORS_START bool validate( const char *strSource, ILog *pLog, const vectorf &pt,\
IPhysicsStreamer *pStreamer, void *param0, int param1, int param2 ) { bool res=true; char errmsg[256];
#define VALIDATOR(member) if (!is_unused(member) && !is_valid(member)) { \
res=false; sprintf(errmsg,"\002%s: (%.50s @ %.1f,%.1f,%.1f) Validation Error: %s is invalid",strSource,\
pStreamer->GetForeignName(param0,param1,param2),pt.x,pt.y,pt.z,#member); \
VALIDATOR_LOG(pLog,errmsg); }
#define VALIDATOR_NORM(member) if (!is_unused(member) && !(is_valid(member) && fabs_tpl((member|member)-1.0f)<0.01f)) { \
res=false; sprintf(errmsg,"\002%s: (%.50s @ %.1f,%.1f,%.1f) Validation Error: %s is invalid or unnormalized",\
strSource,pStreamer->GetForeignName(param0,param1,param2),pt.x,pt.y,pt.z,#member); VALIDATOR_LOG(pLog,errmsg); }
#define VALIDATOR_NORM_MSG(member,msg,member1) if (!is_unused(member) && !(is_valid(member) && fabs_tpl((member|member)-1.0f)<0.01f)) { \
res=false; sprintf(errmsg,"\002%s: (%.50s @ %.1f,%.1f,%.1f) Validation Error: %s is invalid or unnormalized %s",\
strSource,pStreamer->GetForeignName(param0,param1,param2),pt.x,pt.y,pt.z,#member,msg); \
if (!is_unused(member1)) sprintf(errmsg+strlen(errmsg)," "#member1": %.1f,%.1f,%.1f",member1.x,member1.y,member1.z); \
VALIDATOR_LOG(pLog,errmsg); }
#define VALIDATOR_RANGE(member,minval,maxval) if (!is_unused(member) && !(is_valid(member) && member>=minval && member<=maxval)) { \
res=false; sprintf(errmsg,"\002%s: (%.50s @ %.1f,%.1f,%.1f) Validation Error: %s is invalid or out of range",\
strSource,pStreamer->GetForeignName(param0,param1,param2),pt.x,pt.y,pt.z,#member); VALIDATOR_LOG(pLog,errmsg); }
#define VALIDATOR_RANGE2(member,minval,maxval) if (!is_unused(member) && !(is_valid(member) && member*member>=minval*minval && \
member*member<=maxval*maxval)) { \
res=false; sprintf(errmsg,"\002%s: (%.50s @ %.1f,%.1f,%.1f) Validation Error: %s is invalid or out of range",\
strSource,pStreamer->GetForeignName(param0,param1,param2),pt.x,pt.y,pt.z,#member); VALIDATOR_LOG(pLog,errmsg); }
#define VALIDATORS_END return res; }
#define ENTITY_VALIDATE(strSource,pStructure) if (!pStructure->validate(strSource,m_pWorld->m_pLog,m_pos,\
m_pWorld->m_pPhysicsStreamer,m_pForeignData,m_iForeignData,m_iForeignFlags)) { \
if (m_pWorld->m_vars.bBreakOnValidation) DoBreak return 0; }
#define ENTITY_VALIDATE_ERRCODE(strSource,pStructure,iErrCode) if (!pStructure->validate(strSource,m_pWorld->m_pLog,m_pos, \
m_pWorld->m_pPhysicsStreamer,m_pForeignData,m_iForeignData,m_iForeignFlags)) { \
if (m_pWorld->m_vars.bBreakOnValidation) DoBreak return iErrCode; }
#endif //LINUX
#endif

183
CryPhysics/vectorn.h Normal file
View File

@@ -0,0 +1,183 @@
//////////////////////////////////////////////////////////////////////
//
// Variable-length Vector header
//
// File: vectorn.h
// Description : vectorn template class declaration and inlined implementation
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#ifndef vectorn_h
#define vectorn_h
#pragma once
template <class ftype> class matrix_vector_product_tpl {
public:
matrix_vector_product_tpl(int nrows,int ncols,ftype *pmtxdata, ftype *pvecdata) {
nRows=nrows; nCols=ncols; mtxdata=pmtxdata; vecdata=pvecdata;
}
int nRows,nCols;
ftype *mtxdata,*vecdata;
};
template <class ftype> class vectorn_tpl {
public:
vectorn_tpl(int _len,ftype *pdata=0) {
len = _len;
if (pdata) { flags=mtx_foreign_data; data=pdata; }
#ifdef USE_MATRIX_POOLS
else if (len<64) {
if (vecn_pool_pos+len > vecn_pool_size)
vecn_pool_pos = 0;
data = vecn_pool+vecn_pool_pos;
vecn_pool_pos += len;
flags = mtx_foreign_data;
}
#endif
else { data=new ftype[len]; flags=0; }
}
vectorn_tpl(vectorn_tpl &src) { flags=src.flags & mtx_foreign_data; data=src.data; len=src.len; src.flags |= mtx_foreign_data; };
~vectorn_tpl() { if (!(flags & mtx_foreign_data)) delete[] data; }
vectorn_tpl& operator=(const vectorn_tpl<ftype> &src) {
if (src.len!=len && !(flags & mtx_foreign_data)) {
if (data) delete data;
data = new ftype[src.len];
}
len = src.len;
for(int i=0;i<len;i++) data[i]=src.data[i];
return *this;
}
template<class ftype1> vectorn_tpl& operator=(const vectorn_tpl<ftype1> &src) {
if (src.len!=len && !(flags & mtx_foreign_data)) {
if (data) delete data;
data = new ftype[src.len];
}
len = src.len;
for(int i=0;i<len;i++) data[i]=src.data[i];
return *this;
}
vectorn_tpl& operator=(const matrix_vector_product_tpl<ftype> &src) {
int i,j;
for(i=0;i<src.nRows;i++) for(data[i]=0,j=0;j<src.nCols;j++)
data[i] += src.mtxdata[i*src.nCols+j]*src.vecdata[j];
return *this;
}
vectorn_tpl& operator+=(const matrix_vector_product_tpl<ftype> &src) {
int i,j;
for(i=0;i<src.nRows;i++) for(j=0;j<src.nCols;j++)
data[i] += src.mtxdata[i*src.nCols+j]*src.vecdata[j];
return *this;
}
vectorn_tpl& operator-=(const matrix_vector_product_tpl<ftype> &src) {
int i,j;
for(i=0;i<src.nRows;i++) for(j=0;j<src.nCols;j++)
data[i] -= src.mtxdata[i*src.nCols+j]*src.vecdata[j];
return *this;
}
ftype len2() { ftype res=0; for(int i=0;i<len;i++) res += data[i]*data[i]; return res; }
ftype& operator[](int idx) const { return data[idx]; }
operator ftype*() { return data; }
vectorn_tpl& zero() { for(int i=0;i<len;i++) data[i]=0; return *this; }
vectorn_tpl& allocate() {
if (flags & mtx_foreign_data) {
ftype *newdata = new ftype[len];
for(int i=0;i<len;i++) newdata[i]=data[i];
data=newdata; flags&=~mtx_foreign_data;
}
}
vectorn_tpl operator*(ftype op) const {
vectorn_tpl<ftype> res(len);
for(int i=0;i<len;i++) res.data[i] = data[i]*op;
return res;
}
vectorn_tpl& operator*=(ftype op) {
for(int i=0;i<len;i++) data[i] *= op;
return *this;
}
ftype *data;
int len;
int flags;
#ifdef USE_MATRIX_POOLS
static ftype vecn_pool[];
static int vecn_pool_pos;
static int vecn_pool_size;
#endif
};
template<class ftype1,class ftype2>
ftype1 operator*(const vectorn_tpl<ftype1>& op1, const vectorn_tpl<ftype2>& op2) {
ftype1 res=0; for(int i=0;i<op1.len;i++) res += op1.data[i]*op2.data[i];
return res;
}
/*template<class ftype1,class ftype2>
vectorn_tpl<ftype1> operator+(const vectorn_tpl<ftype1> &op1,const vectorn_tpl<ftype2> &op2) {
vectorn_tpl<ftype1> res(len);
for(int i=0;i<len;i++) res.data[i] = op1.data[i]+op2.data[i];
return res;
}
*/
template<class ftype1,class ftype2>
vectorn_tpl<ftype1> operator-(const vectorn_tpl<ftype1> &op1, const vectorn_tpl<ftype2> &op2) {
vectorn_tpl<ftype1> res(op1.len);
for(int i=0;i<op1.len;i++) res.data[i] = op1.data[i]-op2.data[i];
return res;
}
template<class ftype1,class ftype2>
vectorn_tpl<ftype1>& operator+=(vectorn_tpl<ftype1> &op1, const vectorn_tpl<ftype2> &op2) {
for(int i=0;i<op1.len;i++) op1.data[i] += op2.data[i];
return op1;
}
template<class ftype1,class ftype2>
vectorn_tpl<ftype1>& operator-=(vectorn_tpl<ftype1> &op1, const vectorn_tpl<ftype2> &op2) {
for(int i=0;i<op1.len;i++) op1.data[i]-=op2.data[i];
return op1;
}
template<class ftype1,class ftype2>
vectorn_tpl<ftype1> operator*(const vectorn_tpl<ftype1> &vec, const matrix_tpl<ftype2> &mtx) {
int i,j; vectorn_tpl<ftype1> res(mtx.nCols);
for(i=0;i<mtx.nCols;i++) for(res.data[i]=0,j=0;j<vec.len;j++)
res.data[i] += vec[j]*mtx[j][i];
return res;
}
/*template<class ftype1,class ftype2>
vectorn_tpl<ftype1> operator*(const matrix_tpl<ftype1> &mtx, const vectorn_tpl<ftype2> &vec) {
int i,j; vectorn_tpl<ftype1> res(mtx.nRows);
for(i=0;i<mtx.nRows;i++) for(res.data[i]=0,j=0;j<vec.len;j++)
res.data[i] += mtx[i][j]*vec[j];
return res;
}*/
template<class ftype>
matrix_vector_product_tpl<ftype> operator*(const matrix_tpl<ftype> &mtx, const vectorn_tpl<ftype> &vec) {
return matrix_vector_product_tpl<ftype>(mtx.nRows,mtx.nCols,mtx.data, vec.data);
}
typedef vectorn_tpl<float> vectornf;
typedef vectorn_tpl<real> vectorn;
#if defined(LINUX)
#define DECLARE_VECTORN_POOL(ftype,sz) template<> ftype vectorn_tpl<ftype>::vecn_pool[sz] = {}; template<> int vectorn_tpl<ftype>::vecn_pool_pos=0; \
template<> int vectorn_tpl<ftype>::vecn_pool_size=sz;
#else
#define DECLARE_VECTORN_POOL(ftype,sz) template<> ftype vectorn_tpl<ftype>::vecn_pool[sz]; template<> int vectorn_tpl<ftype>::vecn_pool_pos=0; \
template<> int vectorn_tpl<ftype>::vecn_pool_size=sz;
#endif //LINUX
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,115 @@
//////////////////////////////////////////////////////////////////////
//
// Wheeled Vehicle Entity header
//
// File: wheeledvehicleentity.h
// Description : CWheeledVehicleEntity class declaration
//
// History:
// -:Created by Anton Knyazev
//
//////////////////////////////////////////////////////////////////////
#ifndef wheeledvehicleentity_h
#define wheeledvehicleentity_h
#pragma once
struct suspension_point {
int bDriving; // if the corresponding wheel a driving wheel
int iAxle;
vectorf pt; // the uppermost suspension point in car frame
float fullen; // unconstrained length
float kStiffness; // stiffness coefficient
float kDamping,kDamping0; // damping coefficient
float len0; // initial length in model
float Mpt; // hull "mass" at suspension upper point along suspension direction
quaternionf q0; // used to calculate geometry transformation from wheel transformation
vectorf pos0,ptc0; // ...
float Iinv;
float minFriction,maxFriction;
int flags0,flagsCollider0;
int bCanBrake;
int iBuddy;
float r,rinv; // wheel radius, 1.0/radius
float width;
float curlen; // current length
float steer; // steering angle
float rot; // current wheel rotation angle
float w; // current rotation speed
float wa; // current angular acceleration
float T; // wheel's net torque
float prevTdt;
float prevw;
vectorf ncontact,ptcontact; // filled in RegisterPendingCollisions
int bSlip,bSlipPull;
int bContact;
int surface_idx[2];
vectorf vrel;
vectorf rworld;
float vworld;
float PN;
RigidBody *pbody;
CPhysicalEntity *pent;
int ipart;
};
class CWheeledVehicleEntity : public CRigidEntity, public IRigidBodyOwner {
public:
CWheeledVehicleEntity(CPhysicalWorld *pworld);
virtual pe_type GetType() { return PE_WHEELEDVEHICLE; }
virtual int SetParams(pe_params*);
virtual int GetParams(pe_params*);
virtual int Action(pe_action*);
virtual int GetStatus(pe_status*);
enum snapver { SNAPSHOT_VERSION = 1 };
virtual int GetSnapshotVersion() { return SNAPSHOT_VERSION; }
virtual int GetStateSnapshot(class CStream &stm, float time_back=0, int flags=0);
virtual int SetStateFromSnapshot(class CStream &stm, int flags=0);
virtual int AddGeometry(phys_geometry *pgeom, pe_geomparams* params,int id=-1);
virtual void RemoveGeometry(int id);
virtual float GetMaxTimeStep(float time_interval);
virtual float GetDamping(float time_interval);
virtual void CheckAdditionalGeometry(float time_interval, masktype &contact_mask);
virtual int HasContactsWith(CPhysicalEntity *pent);
virtual void AddAdditionalImpulses(float time_interval);
virtual int Update(float time_interval, float damping);
virtual void ComputeBBox();
//virtual RigidBody *GetRigidBody(int ipart=-1) { return &m_bodyStatic; }
virtual void AddImpulseAtContact(entity_contact *pcontact, int iop, const vectorf &dP) {};
virtual vectorf GetVelocityAtContact(entity_contact *pcontact, int iop) { return vectorf(zero); };
virtual int OnRegisterContact(entity_contact *pcontact, int iop);
virtual void OnSolverEvent(int iEvent) {};
virtual void GetMemoryStatistics(ICrySizer *pSizer);
void UpdateWheelsGeoms();
void RecalcSuspStiffness();
float ComputeDrivingTorque(float time_interval);
suspension_point m_susp[8];
float m_enginePower,m_maxSteer;
float m_engineMaxw,m_engineMinw,m_engineIdlew,m_engineShiftUpw,m_engineShiftDownw,m_gearDirSwitchw,m_engineStartw;
float m_axleFriction,m_brakeTorque,m_clutchSpeed,m_maxBrakingFriction,m_kDynFriction,m_slipThreshold;
float m_kStabilizer;
float m_enginePedal,m_steer,m_clutch,m_wengine;
float m_gears[8];
int m_nGears,m_iCurGear;
int m_bHandBrake;
int m_nHullParts;
int m_iIntegrationType;
float m_EminRigid,m_EminVehicle;
float m_maxAllowedStepVehicle,m_maxAllowedStepRigid;
float m_dampingVehicle;
vectorf m_Ffriction,m_Tfriction;
float m_timeNoContacts;
int m_nContacts,m_bHasContacts;
};
#endif