//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// #include "cbase.h" #include "physics_fluid.h" #include "ivp_compact_surface.hxx" #include "ivp_surman_polygon.hxx" #include "ivp_phantom.hxx" #include "ivp_controller_buoyancy.hxx" #include "ivp_liquid_surface_descript.hxx" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" // NOTE: This is auto-deleted by the phantom controller class CBuoyancyAttacher : public IVP_Attacher_To_Cores_Buoyancy { public: virtual IVP_Template_Buoyancy *get_parameters_per_core( IVP_Core *pCore ); CBuoyancyAttacher(IVP_Template_Buoyancy &templ, IVP_U_Set_Active *set_of_cores_, IVP_Liquid_Surface_Descriptor *liquid_surface_descriptor_); float m_density; }; CPhysicsFluidController::CPhysicsFluidController( CBuoyancyAttacher *pBuoy, IVP_Liquid_Surface_Descriptor *pLiquid, CPhysicsObject *pObject, int nContents ) { m_pBuoyancy = pBuoy; m_pLiquidSurface = pLiquid; m_pObject = pObject; m_nContents = nContents; } CPhysicsFluidController::~CPhysicsFluidController( void ) { delete m_pLiquidSurface; } void CPhysicsFluidController::SetGameData( void *pGameData ) { m_pGameData = pGameData; } void *CPhysicsFluidController::GetGameData( void ) const { return m_pGameData; } void CPhysicsFluidController::GetSurfacePlane( Vector *pNormal, float *pDist ) const { IVP_U_Float_Hesse surface; IVP_U_Float_Point abs_speed_of_current; m_pLiquidSurface->calc_liquid_surface( GetIVPObject()->get_core()->environment, GetIVPObject()->get_core(), &surface, &abs_speed_of_current ); ConvertPlaneToHL( surface, pNormal, pDist ); if ( pNormal ) { *pNormal *= -1; } if ( pDist ) { *pDist *= -1; } } IVP_Real_Object *CPhysicsFluidController::GetIVPObject() { return m_pObject->GetObject(); } const IVP_Real_Object *CPhysicsFluidController::GetIVPObject() const { return m_pObject->GetObject(); } float CPhysicsFluidController::GetDensity() const { return m_pBuoyancy->m_density; } void CPhysicsFluidController::WakeAllSleepingObjects() { GetIVPObject()->get_controller_phantom()->wake_all_sleeping_objects(); } int CPhysicsFluidController::GetContents() const { return m_nContents; } IVP_Template_Buoyancy *CBuoyancyAttacher::get_parameters_per_core( IVP_Core *pCore ) { if ( pCore ) { IVP_Real_Object *pivp = pCore->objects.element_at(0); CPhysicsObject *pPhys = static_cast(pivp->client_data); // This ratio is for objects whose mass / (collision model) volume is not equal to their density. // Keep the fluid pressure/friction solution for the volume, but scale the buoyant force calculations // to be in line with the object's real density. This is accompilshed by changing the fluid's density // on a per-object basis. float ratio = pPhys->GetBuoyancyRatio(); if ( pPhys->GetShadowController() || !(pPhys->CallbackFlags() & CALLBACK_DO_FLUID_SIMULATION) ) { // NOTE: don't do buoyancy on these guys for now! template_buoyancy.medium_density = 0; } else { template_buoyancy.medium_density = m_density * ratio; } } else { template_buoyancy.medium_density = m_density; } return &template_buoyancy; } CBuoyancyAttacher::CBuoyancyAttacher(IVP_Template_Buoyancy &templ, IVP_U_Set_Active *set_of_cores_, IVP_Liquid_Surface_Descriptor *liquid_surface_descriptor_) :IVP_Attacher_To_Cores_Buoyancy(templ, set_of_cores_, liquid_surface_descriptor_) { m_density = templ.medium_density; } //----------------------------------------------------------------------------- // Defines the surface descriptor in local space //----------------------------------------------------------------------------- class CLiquidSurfaceDescriptor : public IVP_Liquid_Surface_Descriptor { public: CLiquidSurfaceDescriptor( CPhysicsObject *pFluidObject, const Vector4D &plane, const Vector ¤t ) { cplane_t worldPlane; worldPlane.normal = plane.AsVector3D(); worldPlane.dist = plane[3]; matrix3x4_t matObjectToWorld; pFluidObject->GetPositionMatrix( &matObjectToWorld ); MatrixITransformPlane( matObjectToWorld, worldPlane, m_objectSpacePlane ); VectorIRotate( current, matObjectToWorld, m_vecObjectSpaceCurrent ); m_pFluidObject = pFluidObject; } virtual void calc_liquid_surface( IVP_Environment * /*environment*/, IVP_Core * /*core*/, IVP_U_Float_Hesse *surface_normal_out, IVP_U_Float_Point *abs_speed_of_current_out) { cplane_t worldPlane; matrix3x4_t matObjectToWorld; m_pFluidObject->GetPositionMatrix( &matObjectToWorld ); MatrixTransformPlane( matObjectToWorld, m_objectSpacePlane, worldPlane ); worldPlane.normal *= -1.0f; worldPlane.dist *= -1.0f; IVP_U_Float_Hesse worldSurface; ConvertPlaneToIVP( worldPlane.normal, worldPlane.dist, worldSurface ); surface_normal_out->set(&worldSurface); surface_normal_out->hesse_val = worldSurface.hesse_val; Vector worldSpaceCurrent; VectorRotate( m_vecObjectSpaceCurrent, matObjectToWorld, worldSpaceCurrent ); IVP_U_Float_Point ivpWorldSpaceCurrent; ConvertDirectionToIVP( worldSpaceCurrent, ivpWorldSpaceCurrent ); abs_speed_of_current_out->set( &ivpWorldSpaceCurrent ); } private: Vector m_vecObjectSpaceCurrent; cplane_t m_objectSpacePlane; CPhysicsObject *m_pFluidObject; }; CPhysicsFluidController *CreateFluidController( IVP_Environment *pEnvironment, CPhysicsObject *pFluidObject, fluidparams_t *pParams ) { pFluidObject->BecomeTrigger(); IVP_Controller_Phantom *pPhantom = pFluidObject->GetObject()->get_controller_phantom(); if ( !pPhantom ) return NULL; IVP_Liquid_Surface_Descriptor *lsd = new CLiquidSurfaceDescriptor( pFluidObject, pParams->surfacePlane, pParams->currentVelocity ); int surfaceprops = pFluidObject->GetMaterialIndex(); float density = physprops->GetSurfaceData( surfaceprops )->physics.density; // --------------------------------------------- // create parameter template for Buoyancy_Solver // --------------------------------------------- // UNDONE: Expose these other parametersd IVP_Template_Buoyancy buoyancy_input; buoyancy_input.medium_density = ConvertDensityToIVP(density); // density of water (unit: kg/m^3) buoyancy_input.pressure_damp_factor = pParams->damping; buoyancy_input.viscosity_factor = 0.0f; buoyancy_input.torque_factor = 0.01f; buoyancy_input.viscosity_input_factor = 0.1f; // ------------------------------------------------------------------------------- // create "water" (i.e. buoyancy solver) and attach a dynamic list of object cores // ------------------------------------------------------------------------------- CBuoyancyAttacher *attacher_to_cores_buoyancy = new CBuoyancyAttacher( buoyancy_input, pPhantom->get_intruding_cores(), lsd ); CPhysicsFluidController *pFluid = new CPhysicsFluidController( attacher_to_cores_buoyancy, lsd, pFluidObject, pParams->contents ); pFluid->SetGameData( pParams->pGameData ); pPhantom->client_data = static_cast(pFluid); return pFluid; } bool SavePhysicsFluidController( const physsaveparams_t ¶ms, CPhysicsFluidController *pFluidObject ) { return false; } bool RestorePhysicsFluidController( const physrestoreparams_t ¶ms, CPhysicsFluidController **ppFluidObject ) { return false; }