/// <summary> /// Prepares rendering (Loads all needed resources). /// </summary> /// <param name="renderState">Current render state.</param> internal void PrepareRendering(RenderState renderState) { List <SceneObject>?invalidObjects = null; // Load all resources var sceneObjectArrayLength = this.ObjectsInternal.Count; var sceneObjectArray = this.ObjectsInternal.BackingArray; for (var loop = 0; loop < sceneObjectArrayLength; loop++) { var actObject = sceneObjectArray[loop]; if (actObject == null) { continue; } try { // Load all resources of the object if (!actObject.IsLoaded(renderState.Device)) { actObject.LoadResources(renderState.Device, renderState.CurrentResources !); } } catch (Exception ex) { // Publish exception info GraphicsCore.PublishInternalExceptionInfo( ex, InternalExceptionLocation.Loading3DObject); //Build list of invalid objects if (invalidObjects == null) { invalidObjects = new List <SceneObject>(); } invalidObjects.Add(actObject); } } //RemoveObject all invalid objects if (invalidObjects != null) { this.HandleInvalidObjects(invalidObjects); } }
/// <summary> /// Adds a resource to the scene /// </summary> /// <typeparam name="TResourceType">The type of the resource.</typeparam> /// <param name="resourceFactory">The factory method which creates the resource object.</param> /// <param name="resourceKey">The key for the newly generated resource.</param> internal NamedOrGenericKey AddResource <TResourceType>(Func <EngineDevice, TResourceType> resourceFactory, NamedOrGenericKey resourceKey) where TResourceType : Resource { resourceFactory.EnsureNotNull(nameof(resourceFactory)); this.InitializeResourceDictionaries(); if (resourceKey == NamedOrGenericKey.Empty) { resourceKey = GraphicsCore.GetNextGenericResourceKey(); } foreach (var actResourceDict in _registeredResourceDicts) { actResourceDict.AddResource(resourceKey, resourceFactory(actResourceDict.Device)); } return(resourceKey); }
/// <summary> /// Prevents a default instance of the <see cref="EngineMainLoop"/> class from being created. /// </summary> internal EngineMainLoop(GraphicsCore graphicsCore) { _host = graphicsCore; _globalLoopAwaitors = new ConcurrentQueue <Action>(); _registeredRenderLoops = new List <RenderLoop>(); _unregisteredRenderLoops = new List <RenderLoop>(); _registeredRenderLoopsLock = new object(); _drawing2DResourcesToUnload = new ConcurrentQueue <Drawing2DResourceBase>(); _scenesForUnload = new List <Scene>(); _scenesForUnloadLock = new object(); _cachedInputEventArgs = new GenericInputEventArgs(); _logicUpdateAndPrepareRendering = new MainLoop_UpdateAndPrepareRendering(graphicsCore, this); _logicRenderAndUpdateBeside = new MainLoop_RenderAndUpdateBeside(_host, this); }
/// <summary> /// Handles invalid objects. /// </summary> /// <param name="invalidObjects">List containing all invalid objects to handle.</param> private void HandleInvalidObjects(List <SceneObject> invalidObjects) { foreach (var actObject in invalidObjects) { //Unload the object if it is loaded try { actObject.UnloadResources(); } catch (Exception ex) { // Publish exception info GraphicsCore.PublishInternalExceptionInfo( ex, InternalExceptionLocation.UnloadingInvalid3DObject); } //RemoveObject this object from this layer this.RemoveObject(actObject); } }
/// <summary> /// Loads a bitmap using WIC. /// </summary> /// <param name="inStream">The stream from which to load the texture file.</param> public static WicBitmapSourceInternal LoadBitmapSource(Stream inStream) { inStream.EnsureNotNull(nameof(inStream)); inStream.EnsureReadable(nameof(inStream)); GraphicsCore.EnsureGraphicsSupportLoaded(); var wicFactory = GraphicsCore.Current.FactoryWIC; var bitmapDecoder = wicFactory !.CreateDecoderFromStream( inStream, DecodeOptions.CacheOnDemand); var formatConverter = wicFactory.CreateFormatConverter(); formatConverter.Initialize( bitmapDecoder.GetFrame(0), DEFAULT_WIC_BITMAP_FORMAT, BitmapDitherType.None, null, 0.0, BitmapPaletteType.Custom); return(new WicBitmapSourceInternal(bitmapDecoder, formatConverter)); }
/// <summary> /// Starts the engine's main loop. /// </summary> /// <param name="cancelToken"></param> /// <returns></returns> internal Task Start(CancellationToken cancelToken) { if (_runningTask != null) { throw new SeeingSharpGraphicsException("Unable to start engine's main loop: Loop has already started!"); } _runningTask = Task.Factory.StartNew(async() => { var renderStopWatch = new Stopwatch(); renderStopWatch.Start(); var renderingRenderLoops = new List <RenderLoop>(16); var scenesToRender = new List <Scene>(16); var camerasToUpdate = new List <Camera3DBase>(16); var devicesInUse = new List <EngineDevice>(16); var inputFrames = new List <InputFrame>(16); var updateState = new UpdateState(TimeSpan.Zero, null); while (!cancelToken.IsCancellationRequested) { var exceptionOccurred = false; try { using (_host.BeginMeasureActivityDuration(SeeingSharpConstants.PERF_GLOBAL_PER_FRAME)) { // Wait some time before doing anything.. var lastRenderMilliseconds = renderStopWatch.GetTrueElapsedMilliseconds(); var delayTime = SeeingSharpConstants.MINIMUM_FRAME_TIME_MS - lastRenderMilliseconds; if (delayTime < SeeingSharpConstants.MINIMUM_DELAY_TIME_MS) { delayTime = SeeingSharpConstants.MINIMUM_DELAY_TIME_MS; } using (_host.BeginMeasureActivityDuration(SeeingSharpConstants.PERF_GLOBAL_WAIT_TIME)) { SeeingSharpUtil.MaximumDelay(delayTime); } // Get all render loops renderingRenderLoops.Clear(); lock (_registeredRenderLoopsLock) { renderingRenderLoops.AddRange(_registeredRenderLoops); } // Queries for devices / scenes in use QueryForScenesAndCameras(renderingRenderLoops, scenesToRender, camerasToUpdate); QueryForDevicesInUse(renderingRenderLoops, devicesInUse); var deviceInUseCount = devicesInUse.Count; // Handle device lost events for (var loop = 0; loop < deviceInUseCount; loop++) { var actDevice = devicesInUse[loop]; if (!actDevice.IsLost) { continue; } actDevice.RecreateAfterDeviceLost(); } // Cleanup device resources for (var loop = 0; loop < deviceInUseCount; loop++) { var actDevice = devicesInUse[loop]; actDevice.CleanupDeviceResourceCollection(); } // Get all input frames _host.InputGatherer !.QueryForCurrentFrames(inputFrames); // Build new UpdateState object var updateTime = renderStopWatch.Elapsed; if (updateTime.TotalMilliseconds > 100.0) { updateTime = TimeSpan.FromMilliseconds(100.0); } updateState.Reset(updateTime, inputFrames); // Restart the stopwatch renderStopWatch.Restart(); // First global pass: Update scene and prepare rendering _logicUpdateAndPrepareRendering.SetPassParameters(renderingRenderLoops, scenesToRender, devicesInUse, updateState); await _logicUpdateAndPrepareRendering.ExecutePassAsync() .ConfigureAwait(false); // Update all cameras foreach (var actCamera in camerasToUpdate) { actCamera.AnimationHandler.Update(updateState); } // Queries for devices / scenes in use (may have changed during prepare) QueryForScenesAndCameras(renderingRenderLoops, scenesToRender, camerasToUpdate); QueryForDevicesInUse(renderingRenderLoops, devicesInUse); // Second global pass: Render scene(s) and update beside _logicRenderAndUpdateBeside.SetPassParameters(renderingRenderLoops, scenesToRender, devicesInUse, updateState); _logicRenderAndUpdateBeside.ExecutePass(); // Raise generic input event (if registered) _cachedInputEventArgs.NotifyNewPass(inputFrames); try { this.GenericInput?.Raise(this, _cachedInputEventArgs); } catch (Exception ex) { GraphicsCore.PublishInternalExceptionInfo(ex, InternalExceptionLocation.EngineMainLoop_GenericInputEvent); } // Clear unreferenced Scenes finally lock (_scenesForUnloadLock) { foreach (var actScene in _scenesForUnload) { actScene.UnloadResources(); actScene.Clear(true); } _scenesForUnload.Clear(); } // Unload all Direct2D resources which are not needed anymore while (_drawing2DResourcesToUnload.TryDequeue(out var act2DResourceToUnload)) { var deviceCount = _host.DeviceCount; for (var loop = 0; loop < deviceCount; loop++) { act2DResourceToUnload.UnloadResources(_host.Devices[loop]); } } } } catch (Exception ex) { exceptionOccurred = true; // Publish exception info GraphicsCore.PublishInternalExceptionInfo(ex, InternalExceptionLocation.EngineMainLoop_Loop); } // Execute global awaitors var prevCount = _globalLoopAwaitors.Count; var currentIndex = 0; while (currentIndex < prevCount) { currentIndex++; if (_globalLoopAwaitors.TryDequeue(out var currentAction)) { currentAction(); } } if (exceptionOccurred) { // Wait some time and try rendering again await Task.Delay(1000); } // Handle suspend / resume var suspendWaiter = _suspendWaiter; if (suspendWaiter != null) { _suspendCallWaiterSource !.TrySetResult(null); // Wait for resuming await suspendWaiter; } // Trigger calculation of performance values _host.PerformanceAnalyzer !.CalculateResults(); } }); return(_runningTask); }
/// <summary> /// Adds the given resource to the dictionary. /// </summary> /// <param name="resource">The resource to add.</param> /// <param name="resourceKey">The key of the resource.</param> internal TResourceType AddResource <TResourceType>(NamedOrGenericKey resourceKey, TResourceType resource) where TResourceType : Resource { resource.EnsureNotNull(nameof(resource)); //Perform some checks if (resource.Dictionary != null) { if (resource.Dictionary == this) { return(resource); } if (resource.Dictionary != this) { throw new ArgumentException("Given resource belongs to another ResourceDictionary!", nameof(resource)); } } //Check given keys if (!resource.IsKeyEmpty && !resourceKey.IsEmpty && resource.Key != resourceKey) { throw new ArgumentException("Unable to override existing key on given resource!"); } //RemoveObject another resource with the same name if (!resource.IsKeyEmpty) { this.RemoveResource(resource.Key); } if (!resourceKey.IsEmpty) { this.RemoveResource(resourceKey); } //Apply a valid key on the given resource object if (resource.Key.IsEmpty) { if (resourceKey.IsEmpty) { resource.Key = GraphicsCore.GetNextGenericResourceKey(); } else { resource.Key = resourceKey; } } //AddObject the resource var newResource = new ResourceInfo(resource); _resources[resource.Key] = newResource; if (newResource.RenderableResource != null) { _renderableResources.Add(newResource.RenderableResource); } if (newResource.UpdatableResource != null) { _updatableResources.Add(newResource.UpdatableResource); } //Register this dictionary on the resource resource.Dictionary = this; return(resource); }
public Task LoadAsync() { return(Task.Factory.StartNew(() => GraphicsCore.Load(this))); }
public void Load() { GraphicsCore.Load(this); }