using System.Threading; namespace Sandbox; /// /// Used for c++ to make callbacks to a camera and be able to find it by id /// internal interface IManagedCamera { static Lock _directoryLock = new(); static Dictionary> _directory = new(); static int _indexer = 1000; static WeakReference _mainCamera; static Lock _mainCameraLock = new(); /// /// Called when entering a specific pipeline stage /// void OnRenderStage( Rendering.Stage renderStage ); /// /// Allocate a camera id for this camera. This is used to find the camera in the c++ code. /// int AllocateCameraId() { Cleanup(); lock ( _directoryLock ) { var cameraId = _indexer++; // We treat 0 as invalid, so skip it if ( cameraId == 0 ) cameraId = _indexer++; _directory[cameraId] = new WeakReference( this ); return cameraId; } } /// /// Find a camera by its id. This is used to find the camera by the calling c++ code. This is called /// in the render thread, so it's important to be thread-safe. /// public static IManagedCamera FindById( int cameraId ) { lock ( _directoryLock ) { if ( !_directory.TryGetValue( cameraId, out var reference ) ) return null; if ( !reference.TryGetTarget( out var cam ) ) return null; return cam; } } public static void SetMainCamera( IManagedCamera camera ) { if ( camera == null ) return; lock ( _mainCameraLock ) { _mainCamera = new WeakReference( camera ); } } public static IManagedCamera GetMainCamera() { lock ( _mainCameraLock ) { if ( _mainCamera == null ) return null; if ( !_mainCamera.TryGetTarget( out var cam ) ) return null; return cam; } } /// /// keep the directory clean by trimming all the old ones /// static void Cleanup() { lock ( _directoryLock ) { foreach ( var old in _directory.Where( x => !x.Value.TryGetTarget( out var _ ) ).Select( x => x.Key ).ToArray() ) { _directory.Remove( old ); } } } }