//===========================================================================// // File: door.cc // // Project: Red Planet // // Contents: Door subsystem for managing door operation // //---------------------------------------------------------------------------// // Date Who Modification // // -------- --- ---------------------------------------------------------- // // // //---------------------------------------------------------------------------// // Copyright (C) 1995, Virtual World Entertainment, Inc. All Rights reserved // // PROPRIETARY AND CONFIDENTIAL // //===========================================================================// #include #pragma hdrstop #if !defined(DOOR_HPP) # include #endif #if !defined(FILEUTIL_HPP) # include #endif #if !defined(BOXSOLID_HPP) # include #endif #if !defined(DOORFRAM_HPP) # include #endif #if !defined(APP_HPP) #include #endif #if !defined(NOTATION_HPP) #include #endif //############################################################################# // Shared Data Support // Door::SharedData Door::DefaultData( Door::ClassDerivations, Door::MessageHandlers, Door::AttributeIndex, Door::StateCount ); Derivation Door::ClassDerivations( Subsystem::ClassDerivations, "Door" ); //############################################################################# // Messaging Support // //############################################################################# // Attribute Support // const Door::IndexEntry Door::AttributePointers[]= { { Door::CurrentPositionAttributeID, "CurrentPosition", (Simulation::AttributePointer)&Door::currentPosition }, { Door::VideoResourceAttributeID, "VideoResource", (Simulation::AttributePointer)&Door::videoResource }, { Door::PercentOpenAttributeID, "PercentOpen", (Simulation::AttributePointer)&Door::percentOpen }, { Door::CurrentVelocityAttributeID, "CurrentVelocity", (Simulation::AttributePointer)&Door::currentVelocity } }; Door::AttributeIndexSet Door::AttributeIndex( ELEMENTS(Door::AttributePointers), Door::AttributePointers, Subsystem::AttributeIndex ); //############################################################################# // Model Support // void Door::ReadUpdateRecord(Simulation::UpdateRecord *message) { Check(this); Check_Pointer(message); Subsystem::ReadUpdateRecord(message); UpdateRecord* record = (UpdateRecord*) message; percentOpen = record->percentOpen; switch (GetSimulationState()) { case Opening: case Closing: phaseTimeRemaining = travelTime; break; case Opened: case Closed: phaseTimeRemaining = deadTime; break; } // DEBUG_STREAM << GetEntity()->GetEntityID() << " door updated to state " // << GetSimulationState() << " @ " // << application->GetSecondsRemainingInGame() << endl; MoveCollisionVolume(percentOpen); Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Door::WriteUpdateRecord(Simulation::UpdateRecord *record, int update_model) { Check(this); Check_Pointer(record); Subsystem::WriteUpdateRecord(record, update_model); UpdateRecord *update = (UpdateRecord*)record; update->percentOpen = percentOpen; update->recordLength = sizeof(*update); Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Door::SlideDoor(Scalar time_slice) { Check(this); // //------------------------------------------------------------ // Advance the clock, then branch based upon our current state //------------------------------------------------------------ // int new_state; if (time_slice > 1.0f) { Check_Fpu(); return; } phaseTimeRemaining -= time_slice; Scalar percent_open; switch (GetSimulationState()) { // //------------------------------------------------------------------------ // If the door is not done opening, set its new position, otherwise branch // to the opened state //------------------------------------------------------------------------ // case Opening: Door_Opening: new_state = Opening; if (phaseTimeRemaining > 0.0f) { percent_open = 1.0f - phaseTimeRemaining/travelTime; } else { phaseTimeRemaining += deadTime; // DEBUG_STREAM << GetEntity()->GetEntityID() << " door opened @ " // << application->GetSecondsRemainingInGame() << endl; goto Door_Opened; } currentVelocity.Subtract( worldExtent, GetEntity()->localOrigin.linearPosition ); currentVelocity /= travelTime; Check_Fpu(); break; // //------------------------------------------------------------- // If the door is ready to start closing, jump to closing state //------------------------------------------------------------- // case Opened: Door_Opened: new_state = Opened; if (phaseTimeRemaining <= 0.0f) { phaseTimeRemaining += travelTime; // DEBUG_STREAM << GetEntity()->GetEntityID() << " door closing @ " // << application->GetSecondsRemainingInGame() << endl; goto Door_Closing; } percent_open = 1.0f; currentVelocity = Vector3D::Identity; Check_Fpu(); break; // //------------------------------------------------------------------------ // If the door is not done closing, set its new position, otherwise branch // to the closed state //------------------------------------------------------------------------ // case DefaultState: phaseTimeRemaining = travelTime; // DEBUG_STREAM << GetEntity()->GetEntityID() << " door default @ " // << application->GetSecondsRemainingInGame() << endl; case Closing: Door_Closing: new_state = Closing; if (phaseTimeRemaining > 0.0f) { percent_open = phaseTimeRemaining/travelTime; } else { phaseTimeRemaining += deadTime; // DEBUG_STREAM << GetEntity()->GetEntityID() << " door closed @ " // << application->GetSecondsRemainingInGame() << endl; goto Door_Closed; } currentVelocity.Subtract( GetEntity()->localOrigin.linearPosition, worldExtent ); currentVelocity /= travelTime; Check_Fpu(); break; // //------------------------------------------------------------- // If the door is ready to start opening, jump to opening state //------------------------------------------------------------- // case Closed: Door_Closed: new_state = Closed; if (phaseTimeRemaining <= 0.0f) { phaseTimeRemaining += travelTime; // DEBUG_STREAM << GetEntity()->GetEntityID() << " door opening @ " // << application->GetSecondsRemainingInGame() << endl; goto Door_Opening; } percent_open = 0.0f; currentVelocity = Vector3D::Identity; Check_Fpu(); break; } // //------------------------------------------------- // Move the collision volumes and set the new state //------------------------------------------------- // MoveCollisionVolume(percent_open); SetSimulationState(new_state); Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Door::MoveCollisionVolume(Scalar percent_open) { Check(this); // //--------------------------------------------------------- // If the door hasn't moved, don't bother updating anything //--------------------------------------------------------- // Entity *entity = GetEntity(); Check(entity); if ( GetSimulationState() != simulationState.GetOldState() && entity->GetInstance() == Entity::MasterInstance && entity->IsDynamic() ) { ForceUpdate(); } if (percent_open == percentOpen) { return; } // //----------------------------------- // Otherwise, lerp the local position //----------------------------------- // percentOpen = percent_open; currentPosition.Lerp(Point3D::Identity, localExtent, percentOpen); // //----------------------------------------------------------- // Now, lerp the world position and set the collision volumes //----------------------------------------------------------- // Point3D world; world.Lerp( GetEntity()->localOrigin.linearPosition, worldExtent, percentOpen ); BoxedSolid* temp = collisionTemplates; BoxedSolid* vol = collisionVolumes; while (temp) { Check(temp); Check(vol); vol->minX = temp->minX + world.x; vol->maxX = temp->maxX + world.x; vol->minY = temp->minY + world.y; vol->maxY = temp->maxY + world.y; vol->minZ = temp->minZ + world.z; vol->maxZ = temp->maxZ + world.z; vol = vol->GetNextSolid(); temp = temp->GetNextSolid(); } Verify(!vol); Check_Fpu(); } //############################################################################# // Constructer/Destructor Support // Door::Door( DoorFrame *entity, int subsystem_ID, SubsystemResource *subsystem_resource ): Subsystem(entity, subsystem_ID, subsystem_resource, DefaultData) { Check_Pointer(this); Check(entity); Check_Pointer(subsystem_resource); // // GetStream data NOTE::This must be in the same order as below!!! // localExtent = subsystem_resource->motionExtent; travelTime = subsystem_resource->travelTime; deadTime = subsystem_resource->deadTime; // // Initialize variables // phaseTimeRemaining = 0.0f; currentPosition = Point3D::Identity; SetPerformance(&Door::SlideDoor); SetSimulationState(DefaultState); collisionVolumeCount = 0; collisionTemplates = NULL; collisionVolumes = NULL; percentOpen = -1.0f; // //------------------------------------- // Establish the worldspace coordinates //------------------------------------- // worldExtent.Multiply(localExtent, entity->localToWorld); Origin local_origin = entity->localOrigin; local_origin.linearPosition = Point3D::Identity; // //------------------------------ // Read in the collision volumes //------------------------------ // Check(application); ResourceFile *res_file = application->GetResourceFile(); Check(res_file); ResourceDescription *res = res_file->FindResourceDescription(subsystem_resource->collisionID); Check(res); res->Lock(); BoxedSolidResource* box = (BoxedSolidResource*)res->resourceAddress; Check_Pointer(box); collisionVolumeCount = res->resourceSize / sizeof(BoxedSolidResource); for (int i=0; ilocalOrigin); local_box.Instance(*box,local_origin); collisionTemplates = BoxedSolid::MakeBoxedSolid(&local_box, this, collisionTemplates); Register_Object(collisionTemplates); collisionVolumes = BoxedSolid::MakeBoxedSolid(&world_box, this, collisionVolumes); Register_Object(collisionVolumes); ++box; } res->Unlock(); MoveCollisionVolume(0.0f); Check(this); } Door::~Door() { BoxedSolid *box = collisionTemplates; while (box) { BoxedSolid *next_box = box->GetNextSolid(); Unregister_Object(box); delete box; box = next_box; } box = collisionVolumes; while (box) { BoxedSolid *next_box = box->GetNextSolid(); Unregister_Object(box); delete box; box = next_box; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CreateStreamedSubsystem // Logical Door::CreateStreamedSubsystem( NotationFile *model_file, const char *model_name, const char* subsystem_name, SubsystemResource *subsystem_resource, NotationFile *subsystem_file, const ResourceDirectories *directories, ResourceFile *res_file ) { if ( !Subsystem::CreateStreamedSubsystem( model_file, model_name, subsystem_name, subsystem_resource, subsystem_file, directories ) ) { return False; } subsystem_resource->subsystemModelSize = sizeof(*subsystem_resource); subsystem_resource->classID = RegisteredClass::DoorClassID; // // Get the motion Extent // const char *extent_data; if( !subsystem_file->GetEntry( subsystem_name, "MotionExtent", &extent_data ) ) { cerr << subsystem_name << " missing MotionExtent!!\n"; return -1; } sscanf( extent_data, "%f %f %f", &subsystem_resource->motionExtent.x, &subsystem_resource->motionExtent.y, &subsystem_resource->motionExtent.z ); // // Get the travelTime // if( !subsystem_file->GetEntry( subsystem_name, "TravelTime", &subsystem_resource->travelTime ) ) { cerr << subsystem_name << " missing TravelTime!\n"; return -1; } // // Read in the Deadtime // if( !subsystem_file->GetEntry( subsystem_name, "DeadTime", &subsystem_resource->deadTime ) ) { cerr << subsystem_name << " missing DeadTime!\n"; return False; } const char* collision_file; if ( !subsystem_file->GetEntry( subsystem_name, "Collision", &collision_file ) ) { cerr << subsystem_name << " missing Collision!\n"; return False; } subsystem_resource->collisionID = BoxedSolidResource::CreateBoxedSolidStream( collision_file, res_file, directories ); return True; } Logical Door::TestInstance() const { return IsDerivedFrom(ClassDerivations); }