#include "munga.h" #pragma hdrstop #include "renderer.h" #include "rndorgn.h" #include "explode.h" #include "app.h" #include "objstrm.h" #include "hostmgr.h" #include "subsystm.h" //############################################################################# //############################ Renderer ################################# //############################################################################# const RendererRate DefaultRendererRate = 30.0f; const RendererComplexity MaxRendererComplexity = 3.0f; const RendererComplexity MinRendererComplexity = 0.0f; const RendererFrameBudget DefaultRendererFrameBudget = 0.14f; //0.12f; // 0.16f; //############################################################################# // Message Support // const Receiver::HandlerEntry Renderer::MessageHandlerEntries[]= { { Renderer::NotifyOfNewInterestingEntityMessageID, "NotifyOfNewInterestingEntity", (Renderer::Handler)&Renderer::NotifyOfNewInterestingEntityMessageHandler }, { Renderer::NotifyOfBecomingUninterestingEntityMessageID, "NotifyOfBecomingUninterestingEntity", (Renderer::Handler)&Renderer::NotifyOfBecomingUninterestingEntityMessageHandler }, { Renderer::StartEntityEffectMessageID, "StartEntityEffect", (Renderer::Handler)&Renderer::StartEntityEffectMessageHandler }, { Renderer::StopAllEntityEffectsMessageID, "StopAllEntityEffects", (Renderer::Handler)&Renderer::StopAllEntityEffectsMessageHandler }, { Renderer::StartEntityAlarmMessageID, "StartEntityAlarm", (Renderer::Handler)&Renderer::StartEntityAlarmMessageHandler }, { Renderer::StopEntityAlarmMessageID, "StopEntityAlarm", (Renderer::Handler)&Renderer::StopEntityAlarmMessageHandler } }; Renderer::MessageHandlerSet& Renderer::GetMessageHandlers() { static Renderer::MessageHandlerSet messageHandlers(ELEMENTS(Renderer::MessageHandlerEntries), Renderer::MessageHandlerEntries, Receiver::GetMessageHandlers()); return messageHandlers; } //############################################################################# // Shared Data Support // Derivation* Renderer::GetClassDerivations() { static Derivation classDerivations(Receiver::GetClassDerivations(), "Renderer"); return &classDerivations; } Renderer::SharedData Renderer::DefaultData( Renderer::GetClassDerivations(), Renderer::GetMessageHandlers() ); // //############################################################################# // Renderer //############################################################################# // Renderer::Renderer( RendererRate calibration_rate, RendererComplexity calibration_complexity, RendererPriority calibration_priority, InterestType interest_type, InterestDepth depth_calibration, ClassID class_ID, SharedData &virtual_data ): Receiver(class_ID, virtual_data), rendererOriginSocket(NULL), entitySocket(NULL) { rendererStatus = InactiveRendererStatus; calibrationRate = calibration_rate; calibrationFrameDuration = 1.0f / calibration_rate; nextRenderTime = 0.0f; Verify(MinRendererComplexity < calibration_complexity); Verify(calibration_complexity <= MaxRendererComplexity); calibrationComplexity = calibration_complexity; calibrationPriority = calibration_priority; interestType = interest_type; depthCalibration = depth_calibration; framePercentBudget = DefaultRendererFrameBudget; Check_Fpu(); } // //############################################################################# // ~Renderer //############################################################################# // Renderer::~Renderer() { UnlinkFromEntity(); Check_Fpu(); } // //############################################################################# // TestInstance //############################################################################# // Logical Renderer::TestInstance() const { if (!IsDerivedFrom(*GetClassDerivations())) { return False; } Check(&rendererOriginSocket); Check(&entitySocket); return True; } // //############################################################################# // LinkToEntity //############################################################################# // void Renderer::LinkToEntity(Entity *entity) { Check(this); Check(entity); // //-------------------------------------------------------------------------- // Unlink from current entity and add new entity //-------------------------------------------------------------------------- // UnlinkFromEntity(); entitySocket.Add(entity); // //-------------------------------------------------------------------------- // Make an interest origin for the given entity //-------------------------------------------------------------------------- // RendererOrigin *rendererOrigin; rendererOrigin = new RendererOrigin( this, entity, interestType, depthCalibration ); Register_Object(rendererOrigin); Check(application); application->GetInterestManager()->AdoptInterestOrigin(rendererOrigin); rendererOriginSocket.Add(rendererOrigin); Check_Fpu(); } // //############################################################################# // UnlinkFromEntity //############################################################################# // void Renderer::UnlinkFromEntity() { Check(this); // //-------------------------------------------------------------------------- // Delete current interest origin //-------------------------------------------------------------------------- // RendererOrigin *rendererOrigin; if ((rendererOrigin = rendererOriginSocket.GetCurrent()) != NULL) { Check(rendererOrigin); // // Remove entity from socket // entitySocket.Remove(); // // Delete the interest origin // Check(application); Check(application->GetInterestManager()); application->GetInterestManager()->OrphanInterestOrigin(rendererOrigin); Unregister_Object(rendererOrigin); delete rendererOrigin; } Check_Fpu(); } // //############################################################################# // LoadMission //############################################################################# // void Renderer::LoadMission(Mission *mission) { Check(this); Verify(rendererStatus == InactiveRendererStatus); rendererStatus = LoadingRendererStatus; nextRenderTime = Now(); Check(application); application->GetRendererManager()->StartRenderer(this); LoadMissionImplementation(mission); Check_Fpu(); } // //############################################################################# // Shutdown //############################################################################# // void Renderer::Shutdown() { Check(this); // //------------------------------------------------- // Shutdown and unhook the renderer if it is active //------------------------------------------------- // if (rendererStatus == InactiveRendererStatus) { return; } rendererStatus = InactiveRendererStatus; Check(application); application->GetRendererManager()->StopRenderer(this); ShutdownImplementation(); Check_Fpu(); } // //############################################################################# // SetRendererStatusToRunning //############################################################################# // void Renderer::SetRendererStatusToRunning() { Verify(rendererStatus == LoadingRendererStatus); rendererStatus = RunningRendererStatus; Check_Fpu(); } // //############################################################################# // UpdateRendererOrigin //############################################################################# // void Renderer::UpdateInterestOrigin(Time target_render_time) { Check(this); // //-------------------------------------------------------------------------- // If the renderer is inactive, skip it //-------------------------------------------------------------------------- // if (rendererStatus == InactiveRendererStatus) return; // //-------------------------------------------------------------------------- // Does the renderer need to run this frame to meet its frame rate? //-------------------------------------------------------------------------- // if (nextRenderTime > target_render_time) return; // //-------------------------------------------------------------------------- // Update the interest origin //-------------------------------------------------------------------------- // Entity *entity; RendererOrigin *rendererOrigin; entity = entitySocket.GetCurrent(); Check(entity); rendererOrigin = rendererOriginSocket.GetCurrent(); Check(rendererOrigin); rendererOrigin->Update(entity->GetInterestZoneID()); Check_Fpu(); } // //############################################################################# // Execute //############################################################################# // void Renderer::Execute( Time target_render_time, RendererComplexity complexity_update ) { Check(this); mTargetRenderTime = target_render_time; // //-------------------------------------------------------------------------- // If the renderer is suspended, skip it //-------------------------------------------------------------------------- // if (rendererStatus == InactiveRendererStatus) return; // //-------------------------------------------------------------------------- // Does the renderer need to run this frame to meet its frame rate? //-------------------------------------------------------------------------- // // if (nextRenderTime > target_render_time) // return; // nextRenderTime += calibrationFrameDuration; nextRenderTime = Now(); nextRenderTime += calibrationFrameDuration; // //-------------------------------------------------------------------------- // Keep track of renderers frame budget //-------------------------------------------------------------------------- // RendererFrameBudget start_percent; RendererFrameBudget end_percent; start_percent = Get_Frame_Percent_Used(); end_percent = start_percent + framePercentBudget; Clamp(end_percent, 0.0f, 1.0f); // //-------------------------------------------------------------------------- // Get interest orign //-------------------------------------------------------------------------- // RendererOrigin *rendererOrigin; rendererOrigin = rendererOriginSocket.GetCurrent(); Check(rendererOrigin); // //-------------------------------------------------------------------------- // Get iterators for the renderers interest origin and execute // renderer //-------------------------------------------------------------------------- // RendererOrigin::InterestingEntityIterator interesting_entity_iterator(rendererOrigin); Check(&interesting_entity_iterator); Time startImplementation = Now(); ExecuteImplementation( complexity_update, &interesting_entity_iterator ); Time endImplementation = Now(); // //-------------------------------------------------------------------------- // If the renderer is under budget then run background if available //-------------------------------------------------------------------------- // RendererFrameBudget current_frame_use; /*for ( current_frame_use = Get_Frame_Percent_Used(); (start_percent < current_frame_use) && (current_frame_use < end_percent); current_frame_use = Get_Frame_Percent_Used() ) { if (!ExecuteBackground()) break; }*/ Check_Fpu(); } // //############################################################################# // NotifyOfNewInterestingEntityMessageHandler //############################################################################# // void Renderer::NotifyOfNewInterestingEntityMessageHandler( NotifyOfNewInterestingEntityMessage *message ) { Check(this); Check(message); Verify(message->messageID == NotifyOfNewInterestingEntityMessageID); Entity *entity; if ((entity = message->GetInterestingEntity()) != NULL) { Check(entity); NotifyOfNewInterestingEntity(entity); } Check_Fpu(); } // //############################################################################# // NotifyOfBecomingUninterestingEntityMessageHandler //############################################################################# // void Renderer::NotifyOfBecomingUninterestingEntityMessageHandler( NotifyOfBecomingUninterestingEntityMessage *message ) { Check(this); Check(message); Verify(message->messageID == NotifyOfBecomingUninterestingEntityMessageID); NotifyOfBecomingUninterestingEntity(message->GetUninterestingEntity()); Check_Fpu(); } // //############################################################################# // StartEntityEffectMessageHandler //############################################################################# // void Renderer::StartEntityEffectMessageHandler( StartEntityEffectMessage *message ) { Check(this); Check(message); Verify(message->messageID == StartEntityEffectMessageID); // //-------------------------------------------------------------------------- // If the entity does not exists then return //-------------------------------------------------------------------------- // Entity *entity; if ((entity = message->GetEntity()) == NULL) return; Check(entity); // //-------------------------------------------------------------------------- // Get the effect model resource //-------------------------------------------------------------------------- // ResourceDescription::ResourceID effect_resource_ID; ResourceDescription *resource_description; Explosion::ModelResource *model_resource; effect_resource_ID = message->GetResourceID(); Check(application); Check(application->GetResourceFile()); resource_description = application->GetResourceFile()->SearchList( effect_resource_ID, ResourceDescription::GameModelResourceType ); Check(resource_description); resource_description->Lock(); model_resource = (Explosion::ModelResource*)resource_description->resourceAddress; Check_Pointer(model_resource); // //-------------------------------------------------------------------------- // If an explosion resource table is being used then use it to set // the resource //-------------------------------------------------------------------------- // if (model_resource->resourceTableObjectID != NullObjectID) { // // Get resource table pointer, // Then set the appropriate resource ID // Plug *plug; ExplosionResourceTable *resource_table; ResourceDescription::ResourceID new_resource_ID; plug = PlugStreamManager::FindPlug(model_resource->resourceTableObjectID); resource_table = Cast_Object(ExplosionResourceTable*, plug); Check(resource_table); new_resource_ID = resource_table->FindResourceID(entity); if (new_resource_ID != ResourceDescription::NullResourceID) { effect_resource_ID = new_resource_ID; } } // //-------------------------------------------------------------------------- // Call the start effect implementation //-------------------------------------------------------------------------- // StartEntityEffectImplementation( entity, message->GetDamageZone(), effect_resource_ID ); resource_description->Unlock(); } // //############################################################################# // StopAllEntityEffectsMessageHandler //############################################################################# // void Renderer::StopAllEntityEffectsMessageHandler( StopAllEntityEffectsMessage *message ) { Check(this); Check(message); Verify(message->messageID == StopAllEntityEffectsMessageID); Entity *entity; if ((entity = message->GetEntity()) != NULL) { Check(entity); StopAllEntityEffectsImplementation(entity); } } // //############################################################################# // StartEntityAlarmMessageHandler //############################################################################# // void Renderer::StartEntityAlarmMessageHandler( StartEntityAlarmMessage *message ) { Check(this); Check(message); Verify(message->messageID == StartEntityAlarmMessageID); Entity *entity; if ((entity = message->GetEntity()) != NULL) { Check(entity); StartEntityAlarmImplementation( entity, message->GetSubsystem(), message->GetCondition(), message->GetResourceID() ); } } // //############################################################################# // StopEntityAlarmMessageHandler //############################################################################# // void Renderer::StopEntityAlarmMessageHandler( StopEntityAlarmMessage *message ) { Check(this); Check(message); Verify(message->messageID == StopEntityAlarmMessageID); Entity *entity; if ((entity = message->GetEntity()) != NULL) { Check(entity); StopEntityAlarmImplementation( entity, message->GetSubsystem(), message->GetCondition() ); } } // //############################################################################# // ExecuteImplementation //############################################################################# // void Renderer::ExecuteImplementation( RendererComplexity, RendererOrigin::InterestingEntityIterator* ) { Fail("Renderer::ExecuteImplementation - Should never reach here"); } // //############################################################################# // LoadMissionImplementation //############################################################################# // void Renderer::LoadMissionImplementation(Mission*) { Fail("Renderer::LoadMissionImplementation - Should never reach here"); } // //############################################################################# // ShutdownImplementation //############################################################################# // void Renderer::ShutdownImplementation() { Fail("Renderer::ShutdownImplementation - Should never reach here"); } //############################################################################# //######################### RendererManager ############################# //############################################################################# // //############################################################################# // RendererManager //############################################################################# // RendererManager::RendererManager(): Receiver(RendererManagerClassID, DefaultData), renderers(NULL) { } // //############################################################################# // ~RendererManager //############################################################################# // RendererManager::~RendererManager() { } // //############################################################################# // TestInstance //############################################################################# // Logical RendererManager::TestInstance() const { Receiver::TestInstance(); Check(&renderers); Check_Fpu(); return True; } // //############################################################################# // StartRenderer //############################################################################# // void RendererManager::StartRenderer(Renderer *renderer) { Check(this); Check(renderer); #if DEBUG_LEVEL>0 SChainIterator iterator(&renderers); Verify(iterator.IsPlugMember(renderer) == False); #endif renderers.Add(renderer); Check_Fpu(); } // //############################################################################# // StopRenderer //############################################################################# // void RendererManager::StopRenderer(Renderer *renderer) { Check(this); Check(renderer); #if DEBUG_LEVEL>0 { SChainIteratorOf iterator(&renderers); Verify(iterator.IsPlugMember(renderer) == True); } #endif SChainIteratorOf iterator(&renderers); iterator.RemovePlug(renderer); Check_Fpu(); } // //############################################################################# // AreRenderersRunning //############################################################################# // Logical RendererManager::AreRenderersRunning() { Check(this); Renderer *renderer; SChainIteratorOf renderers_iterator(&renderers); if (renderers_iterator.GetCurrent() == NULL) return False; while ((renderer = renderers_iterator.ReadAndNext()) != NULL) { Check(renderer); if (renderer->GetRendererStatus() != RunningRendererStatus) return False; } Check_Fpu(); return True; } // //############################################################################# // UpdateInterestOrigins //############################################################################# // void RendererManager::UpdateInterestOrigins(Time target_render_time) { Check(this); // // HACK - under construction, does not include complexity or priorities // Renderer *renderer; SChainIteratorOf renderers_iterator(&renderers); while ((renderer = renderers_iterator.ReadAndNext()) != NULL) { Check(renderer); renderer->UpdateInterestOrigin(target_render_time); } Check_Fpu(); } // //############################################################################# // Execute //############################################################################# // void RendererManager::Execute( Time target_render_time, Time, Time ) { Check(this); // // HACK - under construction, does not include complexity or priorities // Renderer *renderer; RendererComplexity complexity_update; SChainIteratorOf renderers_iterator(&renderers); Time startRender = Now(); int renderItem = 0; while ((renderer = renderers_iterator.ReadAndNext()) != NULL) { Check(renderer); // Calculate current complexity // HACK - use calibration complexity for now Time startComplexity = Now(); complexity_update = renderer->GetCalibrationComplexity(); Time endComplexity = Now(); renderer->Execute(target_render_time, complexity_update); renderItem++; } Time endRender = Now(); endRender = endRender; Check_Fpu(); } // //############################################################################# // ExecuteIdle //############################################################################# // void RendererManager::ExecuteIdle() { Renderer *renderer; SChainIteratorOf renderers_iterator(&renderers); while ((renderer = renderers_iterator.ReadAndNext()) != NULL) { Check(renderer); renderer->ExecuteIdle(); } Check_Fpu(); } // //############################################################################# // PostRendererEvent //############################################################################# // void RendererManager::PostRendererEvent( Entity *entity, Receiver::Message *message ) { Check(this); Check(entity); Check(message); Renderer *renderer; SChainIteratorOf renderers_iterator(&renderers); while ((renderer = renderers_iterator.ReadAndNext()) != NULL) { Check(renderer); Check(application); Check(application->GetInterestManager()); application->GetInterestManager()->PostRendererEvent( entity, renderer, message ); } } //~~~~~~~~~~~~~~~~~ Renderer__NotifyOfNewInterestingEntityMessage ~~~~~~~~~~~~~ Renderer__NotifyOfNewInterestingEntityMessage:: Renderer__NotifyOfNewInterestingEntityMessage( Entity *interesting_entity ): Receiver::Message( Renderer::NotifyOfNewInterestingEntityMessageID, sizeof(Renderer__NotifyOfNewInterestingEntityMessage) ) { Check(interesting_entity); entityID = interesting_entity->GetEntityID(); Check_Fpu(); } Entity* Renderer__NotifyOfNewInterestingEntityMessage::GetInterestingEntity() { Check(this); Check(application); Check(application->GetHostManager()); Check_Fpu(); return application->GetHostManager()->GetEntityPointer(entityID); } //~~~~~~~~~~~~~~ Renderer__NotifyOfBecomingUninterestingEntityMessage ~~~~~~~~~ Renderer__NotifyOfBecomingUninterestingEntityMessage:: Renderer__NotifyOfBecomingUninterestingEntityMessage( Entity *uninteresting_entity ): Receiver::Message( Renderer::NotifyOfBecomingUninterestingEntityMessageID, sizeof(Renderer__NotifyOfBecomingUninterestingEntityMessage) ) { uninterestingEntity = uninteresting_entity; Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~ Renderer__EntityMessage ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Renderer__EntityMessage::Renderer__EntityMessage( Receiver::MessageID message_ID, size_t message_size, Entity *entity ): Receiver::Message( message_ID, message_size ) { Check(entity); entityID = entity->GetEntityID(); } Entity* Renderer__EntityMessage::GetEntity() { Check(this); Check(application); Check(application->GetHostManager()); return application->GetHostManager()->GetEntityPointer(entityID); } //~~~~~~~~~~~~~~~~~~ Renderer__StartEntityEffectMessage ~~~~~~~~~~~~~~~~~~~~~~~ Renderer__StartEntityEffectMessage::Renderer__StartEntityEffectMessage( Entity *entity, DamageZone *damage_zone, ResourceDescription::ResourceID resource_ID ): Renderer__EntityMessage( Renderer::StartEntityEffectMessageID, sizeof(Renderer__StartEntityEffectMessage), entity ) { Check(damage_zone); Verify(resource_ID != ResourceDescription::NullResourceID); damageZone = damage_zone; resourceID = resource_ID; } //~~~~~~~~~~~~~~~~~~ Renderer__StopAllEntityEffectsMessage ~~~~~~~~~~~~~~~~~~~~ Renderer__StopAllEntityEffectsMessage::Renderer__StopAllEntityEffectsMessage( Entity *entity ): Renderer__EntityMessage( Renderer::StopAllEntityEffectsMessageID, sizeof(Renderer__StopAllEntityEffectsMessage), entity ) { } //~~~~~~~~~~~~~~~~~~ Renderer__StartEntityAlarmMessage ~~~~~~~~~~~~~~~~~~~~~~~~ Renderer__StartEntityAlarmMessage::Renderer__StartEntityAlarmMessage( Entity *entity, Subsystem *alarm_subsystem, Enumeration alarm_condition, ResourceDescription::ResourceID resource_ID ): Renderer__EntityMessage( Renderer::StartEntityAlarmMessageID, sizeof(Renderer__StartEntityAlarmMessage), entity ) { Check(alarm_subsystem); #if DEBUG_LEVEL>0 if (resource_ID == ResourceDescription::NullResourceID) { Dump(alarm_subsystem->GetClassID()); Dump(alarm_condition); } #endif Warn(resource_ID == ResourceDescription::NullResourceID); // HACK - ECH Why is this sometimes NULL? subsystem = alarm_subsystem; condition = alarm_condition; resourceID = resource_ID; } //~~~~~~~~~~~~~~~~~~ Renderer__StopEntityAlarmMessage ~~~~~~~~~~~~~~~~~~~~~~~~~ Renderer__StopEntityAlarmMessage::Renderer__StopEntityAlarmMessage( Entity *entity, Subsystem *alarm_subsystem, Enumeration alarm_condition ): Renderer__EntityMessage( Renderer::StopEntityAlarmMessageID, sizeof(Renderer__StopEntityAlarmMessage), entity ) { Check(alarm_subsystem); subsystem = alarm_subsystem; condition = alarm_condition; } #ifdef TEST_CLASS # include "renderer.tcp" #endif