////////////////////////////////////////////////////////////////////////// // haveAnyValidResources BcBool CsPackage::haveAnyValidResources() const { BcAssert( BcIsGameThread() ); // If the data isn't ready, we will have valid resources soon. if( pLoader_->isDataReady() == BcFalse ) { return BcTrue; } // If our resource list is empty we can exit early. if( Resources_.size() == 0 ) { return BcFalse; } // Search through list for all valid resources. for( BcU32 Idx = 0; Idx < Resources_.size(); ++Idx ) { const CsResourceRef<>& Resource( Resources_[ Idx ] ); if( Resource.isValid() == BcTrue ) { return BcTrue; } } // return BcFalse; }
////////////////////////////////////////////////////////////////////////// // getContext //virtual RsContext* RsCoreImplGL::getContext( OsClient* pClient ) { BcAssert( BcIsGameThread() ); TContextMapIterator It = ContextMap_.find( pClient ); if( It != ContextMap_.end() ) { return It->second; } else { if( pClient != NULL ) { RsContextGL* pResource = new RsContextGL( pClient, ContextMap_[ NULL ] ); createResource( pResource ); // If we have no default context, set it. if( ContextMap_[ NULL ] == NULL ) { ContextMap_[ NULL ] = pResource; } // Store mapped to client. ContextMap_[ pClient ] = pResource; return pResource; } } return NULL; }
////////////////////////////////////////////////////////////////////////// // hasUnreferencedResources BcBool CsPackage::hasUnreferencedResources() const { BcAssert( BcIsGameThread() ); // If the data isn't ready, we are still referenced. if( pLoader_->isDataReady() == BcFalse ) { return BcFalse; } BcBool IsUnreferenced = BcTrue; for( BcU32 Idx = 0; Idx < Resources_.size(); ++Idx ) { const CsResourceRef<>& Resource( Resources_[ Idx ] ); // If we've got invalid resources, or a ref count of 1 (self-ref'd) we have unreferenced resources. if( Resource.isValid() == BcFalse || Resource.refCount() == 1 ) { return BcTrue; } } return BcFalse; }
ReEnum* GetEnum( BcName Name ) { auto NameString = ( *Name ); // If it begins with "class", "struct", or "enum", strip it. // NOTE: We should move this work into the demangling stuff. if( NameString.substr( 0, 5 ) == "enum " ) { Name = BcName( NameString.substr( NameString.find( " " ) + 1, NameString.length() - 1 ) ); } // Try find class. ReClass* FoundType = GetType( Name ); if( FoundType == nullptr ) { BcAssertMsg( BcIsGameThread(), "Reflection can only modify database on the game thread." ); FoundType = new ReEnum( Name ); Types_[ Name ] = FoundType; } if( FoundType->isTypeOf< ReEnum >() ) { return static_cast< ReEnum* >( FoundType ); } else { return nullptr; } }
ReClass* GetClass( BcName Name ) { auto NameString = (*Name); // If it begins with "class", "struct", or "enum", strip it. // NOTE: We should move this work into the demangling stuff. if( NameString.substr( 0, 6 ) == "class " || NameString.substr( 0, 7 ) == "struct " || NameString.substr( 0, 5 ) == "enum " ) { Name = BcName( NameString.substr( NameString.find( " " ) + 1, NameString.length() - 1 ) ); } // Try find class. ReClass* FoundType = GetType( Name ); if( FoundType == nullptr ) { BcAssertMsg( BcIsGameThread(), "Reflection can only modify database on the game thread." ); FoundType = new ReClass( Name ); Types_[ Name ] = FoundType; } // Use dynamic cast here instead of our internal RTTI. // It may still be under construction so not yet valid. return dynamic_cast< ReClass* >( FoundType ); }
////////////////////////////////////////////////////////////////////////// // tick void SysKernel::tick() { BcAssert( BcIsGameThread() ); if( ShuttingDown_ == BcFalse ) { BcScopedLock< BcMutex > Lock( SystemLock_ ); // Add systems. addSystems(); // Remove systems. removeSystems(); // Iterate over and process all systems. TSystemListIterator Iter = SystemList_.begin(); while( Iter != SystemList_.end() && ShuttingDown_ == BcFalse ) { // Cache system. SysSystem* pSystem = (*Iter); // Process system. if( pSystem->process() == BcFalse ) { PendingRemoveSystemList_.push_back( pSystem ); } // Next system. ++Iter; } } else { BcScopedLock< BcMutex > Lock( SystemLock_ ); // Iterate over and process all systems. TSystemListReverseIterator Iter = SystemList_.rbegin(); if( Iter != SystemList_.rend() ) { // Cache system. SysSystem* pSystem = (*Iter); // Process system. if( pSystem->process() == BcFalse ) { PendingRemoveSystemList_.push_back( pSystem ); } } // Remove systems. removeSystems(); } // Dispatch callbacks. DelegateDispatcher_.dispatch(); }
////////////////////////////////////////////////////////////////////////// // createResource void RsCoreImplGL::createResource( RsResource* pResource ) { BcAssert( BcIsGameThread() ); // Call create. { SysSystem::CreateDelegate Delegate( SysSystem::CreateDelegate::bind< SysResource, &SysResource::create >( pResource ) ); SysKernel::pImpl()->enqueueDelegateJob( RsCore::WORKER_MASK, Delegate ); } }
////////////////////////////////////////////////////////////////////////// // open //virtual void RsCoreImplGL::open() { BcAssert( BcIsGameThread() ); BcDelegate< void(*)() > Delegate( BcDelegate< void(*)() >::bind< RsCoreImplGL, &RsCoreImplGL::open_threaded >( this ) ); SysKernel::pImpl()->enqueueDelegateJob( RsCore::WORKER_MASK, Delegate ); // Wait for the render thread to complete. SysFence Fence; Fence.queue( RsCore::WORKER_MASK ); Fence.wait(); }
////////////////////////////////////////////////////////////////////////// // allocateFrame RsFrame* RsCoreImplGL::allocateFrame( RsContext* pContext ) { BcAssert( BcIsGameThread() ); if( pContext != NULL ) { return new RsFrameGL( pContext ); } else { return new RsFrameGL( ContextMap_[ NULL ] ); } }
////////////////////////////////////////////////////////////////////////// // destroyResource void RsCoreImplGL::destroyResource( RsResource* pResource ) { BcAssert( BcIsGameThread() ); pResource->preDestroy(); // Call destroy and wait. { SysSystem::DestroyDelegate Delegate( SysSystem::DestroyDelegate::bind< SysResource, &SysResource::destroy >( pResource ) ); SysKernel::pImpl()->enqueueDelegateJob( RsCore::WORKER_MASK, Delegate ); } }
////////////////////////////////////////////////////////////////////////// // update //virtual void RsCoreImplGL::update() { BcAssert( BcIsGameThread() ); // Increment fence so we know how far we're getting ahead of ourselves. RenderSyncFence_.increment(); // Queue update job. BcDelegate< void(*)() > Delegate( BcDelegate< void(*)() >::bind< RsCoreImplGL, &RsCoreImplGL::update_threaded >( this ) ); SysKernel::pImpl()->enqueueDelegateJob( RsCore::WORKER_MASK, Delegate ); // Wait for frames if we fall more than 1 update cycle behind. RenderSyncFence_.wait( 1 ); }
////////////////////////////////////////////////////////////////////////// // destroyContext //virtual void RsCoreImplGL::destroyContext( OsClient* pClient ) { BcAssert( BcIsGameThread() ); TContextMapIterator It = ContextMap_.find( pClient ); if( It != ContextMap_.end() ) { // If we're destroying the default context, NULL it. if( ContextMap_[ NULL ] == It->second ) { ContextMap_[ NULL ] = NULL; } // Destory resource. destroyResource( It->second ); // Erase from context map. ContextMap_.erase( It ); } }
////////////////////////////////////////////////////////////////////////// // releaseUnreferencedResources void CsPackage::releaseUnreferencedResources() { BcAssert( BcIsGameThread() ); // If the data isn't ready, we are still referenced. if( pLoader_->isDataReady() == BcFalse ) { return; } for( BcU32 Idx = 0; Idx < Resources_.size(); ++Idx ) { CsResourceRef<>& Resource( Resources_[ Idx ] ); // Check that the package is the only referencer, if so, NULL it. if( Resource.isValid() && Resource.refCount() == 1 ) { Resource = NULL; } } }
//////////////////////////////////////////////////////////////////////////////// // publishInternal BcBool EvtPublisher::publishInternal( EvtID ID, const EvtBaseEvent& EventBase, BcSize EventSize, BcBool AllowProxy ) { BcAssert( BcIsGameThread() ); BcUnusedVar( EventSize ); #if PSY_USE_PROFILER PSY_PROFILER_INSTANT_EVENT( boost::str( boost::format( "EvtPublisher::publishInternal( ID: %1%, Size: %2% )" ) % ID % EventSize ) ); #endif // Proxy event through all attached proxies if this event allows it. if( AllowProxy == BcTrue ) { for( TProxyListIterator It( Proxies_.begin() ); It != Proxies_.end(); ++It ) { EvtProxy* pProxy( *It ); eEvtReturn RetVal = pProxy->proxy( ID, EventBase, EventSize ); switch( RetVal ) { // Event passed. Publisher, or next proxy can deal with it. case evtRET_PASS: break; // Event blocked. If we are a parent, we want our child publisher to abort (normal behaviour). case evtRET_BLOCK: return BcFalse; break; // Unsupported enum value. default: BcBreakpoint; break; } } } // Update binding map before going ahead. updateBindingMap(); // If we have a parent, publish to them first. BcBool ShouldPublish = BcTrue; if( pParent_ != NULL ) { ShouldPublish = pParent_->publishInternal( ID, EventBase, EventSize ); } // Only publish if the previous call to our parent allows us to. if( ShouldPublish == BcTrue ) { // Find the appropriate binding list. TBindingListMapIterator BindingListMapIterator = BindingListMap_.find( ID ); // Add list if we need to, and grab iterator. if( BindingListMapIterator != BindingListMap_.end() ) { // Iterate over all bindings in list and call. TBindingList& BindingList = BindingListMapIterator->second; TBindingListIterator Iter = BindingList.begin(); while( Iter != BindingList.end() ) { EvtBinding& Binding = (*Iter); // Call binding and handle it's return. eEvtReturn RetVal = Binding( ID, EventBase ); switch( RetVal ) { case evtRET_PASS: ++Iter; break; case evtRET_BLOCK: return BcFalse; break; case evtRET_REMOVE: Iter = BindingList.erase( Iter ); break; default: BcBreakpoint; break; } } } } return BcTrue; }
////////////////////////////////////////////////////////////////////////// // queueFrame void RsCoreImplGL::queueFrame( RsFrame* pFrame ) { BcAssert( BcIsGameThread() ); BcDelegate< void(*)( RsFrameGL* ) > Delegate( BcDelegate< void(*)( RsFrameGL* ) >::bind< RsCoreImplGL, &RsCoreImplGL::queueFrame_threaded >( this ) ); SysKernel::pImpl()->enqueueDelegateJob( RsCore::WORKER_MASK, Delegate, (RsFrameGL*)pFrame ); }
//////////////////////////////////////////////////////////////////////////////// // publishInternal BcBool EvtPublisher::publishInternal( EvtID ID, const EvtBaseEvent& EventBase, BcSize EventSize ) { BcAssert( BcIsGameThread() ); BcUnusedVar( EventSize ); /* { BcChar PrefixA = ( ID >> 24 ) & 0xff; BcChar PrefixB = ( ID >> 16 ) & 0xff; BcU32 Group = ( ID >> 8 ) & 0xff; BcU32 Item = ( ID ) & 0xff; BcPrintf( "EvtPublish: %x, \"%c%c\": Group=%u Item=%u\n", ID, PrefixA, PrefixB, Group, Item ); } //*/ // Update binding map before going ahead. updateBindingMap(); // If we have a parent, publish to them first. BcBool ShouldPublish = BcTrue; if( pParent_ != NULL ) { ShouldPublish = pParent_->publishInternal( ID, EventBase, EventSize ); } // Only publish if the previous call to our parent allows us to. if( ShouldPublish == BcTrue ) { // Find the appropriate binding list. TBindingListMapIterator BindingListMapIterator = BindingListMap_.find( ID ); // Add list if we need to, and grab iterator. if( BindingListMapIterator != BindingListMap_.end() ) { // Iterate over all bindings in list and call. TBindingList& BindingList = BindingListMapIterator->second; TBindingListIterator Iter = BindingList.begin(); while( Iter != BindingList.end() ) { EvtBinding& Binding = (*Iter); // Call binding and handle it's return. eEvtReturn RetVal = Binding( ID, EventBase ); switch( RetVal ) { case evtRET_PASS: ++Iter; break; case evtRET_BLOCK: return BcFalse; break; case evtRET_REMOVE: Iter = BindingList.erase( Iter ); break; default: BcBreakpoint; break; } } } } return BcTrue; }